Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/AlternativeFinder.cc

    r7d01cf44 r00ac42e  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 23:52:08 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Aug  8 16:35:00 2019
    13 // Update Count     : 38
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Feb 17 11:19:39 2018
     13// Update Count     : 33
    1414//
    1515
     
    2525#include <vector>                  // for vector
    2626
    27 #include "CompilationState.h"      // for resolvep
    2827#include "Alternative.h"           // for AltList, Alternative
    2928#include "AlternativeFinder.h"
    30 #include "AST/Expr.hpp"
    31 #include "AST/SymbolTable.hpp"
    32 #include "AST/Type.hpp"
    3329#include "Common/SemanticError.h"  // for SemanticError
    3430#include "Common/utility.h"        // for deleteAll, printAll, CodeLocation
     
    3733#include "InitTweak/InitTweak.h"   // for getFunctionName
    3834#include "RenameVars.h"            // for RenameVars, global_renamer
    39 #include "ResolveAssertions.h"     // for resolveAssertions
    4035#include "ResolveTypeof.h"         // for resolveTypeof
    4136#include "Resolver.h"              // for resolveStmtExpr
     
    5449#include "typeops.h"               // for adjustExprType, polyCost, castCost
    5550
     51extern bool resolvep;
    5652#define PRINT( text ) if ( resolvep ) { text }
    5753//#define DEBUG_COST
     54
     55using std::move;
     56
     57/// copies any copyable type
     58template<typename T>
     59T copy(const T& x) { return x; }
    5860
    5961namespace ResolvExpr {
     
    7981                void postvisit( OffsetofExpr * offsetofExpr );
    8082                void postvisit( OffsetPackExpr * offsetPackExpr );
     83                void postvisit( AttrExpr * attrExpr );
    8184                void postvisit( LogicalExpr * logicalExpr );
    8285                void postvisit( ConditionalExpr * conditionalExpr );
     
    99102                void addAnonConversions( const Alternative & alt );
    100103                /// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
    101                 template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Alternative &alt, const Cost &newCost, const std::string & name );
     104                template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name );
    102105                /// Adds alternatives for member expressions where the left side has tuple type
    103                 void addTupleMembers( TupleType *tupleType, Expression *expr, const Alternative &alt, const Cost &newCost, Expression *member );
     106                void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
    104107                /// Adds alternatives for offsetof expressions, given the base type and name of the member
    105108                template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
     
    109112                /// Finds matching alternatives for a function, given a set of arguments
    110113                template<typename OutputIterator>
    111                 void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs_old& args, OutputIterator out );
    112                 /// Sets up parameter inference for an output alternative
     114                void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
     115                /// Checks if assertion parameters match for a new alternative
    113116                template< typename OutputIterator >
    114                 void inferParameters( Alternative &newAlt, OutputIterator out );
     117                void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
    115118        private:
    116119                AlternativeFinder & altFinder;
     
    130133
    131134        void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) {
    132                 Indenter indent = { indentAmt };
     135                Indenter indent = { Indenter::tabsize, indentAmt };
    133136                for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
    134137                        i->print( os, indent );
     
    173176                                                selected[ mangleName ] = current;
    174177                                        } else if ( candidate->cost == mapPlace->second.candidate->cost ) {
    175                                                 // if one of the candidates contains a deleted identifier, can pick the other, since
    176                                                 // deleted expressions should not be ambiguous if there is another option that is at least as good
    177                                                 if ( findDeletedExpr( candidate->expr ) ) {
    178                                                         // do nothing
    179                                                         PRINT( std::cerr << "candidate is deleted" << std::endl; )
    180                                                 } else if ( findDeletedExpr( mapPlace->second.candidate->expr ) ) {
    181                                                         PRINT( std::cerr << "current is deleted" << std::endl; )
    182                                                         selected[ mangleName ] = current;
    183                                                 } else {
    184                                                         PRINT(
    185                                                                 std::cerr << "marking ambiguous" << std::endl;
    186                                                         )
    187                                                         mapPlace->second.isAmbiguous = true;
    188                                                 }
     178                                                PRINT(
     179                                                        std::cerr << "marking ambiguous" << std::endl;
     180                                                )
     181                                                mapPlace->second.isAmbiguous = true;
    189182                                        } else {
    190183                                                PRINT(
     
    241234        }
    242235
    243         void AlternativeFinder::find( Expression *expr, ResolvMode mode ) {
     236        void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
    244237                PassVisitor<Finder> finder( *this );
    245238                expr->accept( finder );
    246                 if ( mode.failFast && alternatives.empty() ) {
     239                if ( failFast && alternatives.empty() ) {
    247240                        PRINT(
    248241                                std::cerr << "No reasonable alternatives for expression " << expr << std::endl;
     
    250243                        SemanticError( expr, "No reasonable alternatives for expression " );
    251244                }
    252                 if ( mode.satisfyAssns || mode.prune ) {
    253                         // trim candidates just to those where the assertions resolve
    254                         // - necessary pre-requisite to pruning
    255                         AltList candidates;
    256                         std::list<std::string> errors;
    257                         for ( unsigned i = 0; i < alternatives.size(); ++i ) {
    258                                 resolveAssertions( alternatives[i], indexer, candidates, errors );
    259                         }
    260                         // fail early if none such
    261                         if ( mode.failFast && candidates.empty() ) {
    262                                 std::ostringstream stream;
    263                                 stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    264                                 //        << "Alternatives with failing assertions are:\n";
    265                                 // printAlts( alternatives, stream, 1 );
    266                                 for ( const auto& err : errors ) {
    267                                         stream << err;
    268                                 }
    269                                 SemanticError( expr->location, stream.str() );
    270                         }
    271                         // reset alternatives
    272                         alternatives = std::move( candidates );
    273                 }
    274                 if ( mode.prune ) {
     245                if ( prune ) {
    275246                        auto oldsize = alternatives.size();
    276247                        PRINT(
     
    280251                        AltList pruned;
    281252                        pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) );
    282                         if ( mode.failFast && pruned.empty() ) {
     253                        if ( failFast && pruned.empty() ) {
    283254                                std::ostringstream stream;
    284255                                AltList winners;
     
    299270                }
    300271                // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
    301                 if ( mode.adjust ) {
    302                         for ( Alternative& i : alternatives ) {
    303                                 adjustExprType( i.expr->get_result(), i.env, indexer );
     272                for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
     273                        if ( adjust ) {
     274                                adjustExprType( i->expr->get_result(), i->env, indexer );
    304275                        }
    305276                }
     
    313284
    314285        void AlternativeFinder::findWithAdjustment( Expression *expr ) {
    315                 find( expr, ResolvMode::withAdjustment() );
     286                find( expr, true );
    316287        }
    317288
    318289        void AlternativeFinder::findWithoutPrune( Expression * expr ) {
    319                 find( expr, ResolvMode::withoutPrune() );
     290                find( expr, true, false );
    320291        }
    321292
    322293        void AlternativeFinder::maybeFind( Expression * expr ) {
    323                 find( expr, ResolvMode::withoutFailFast() );
     294                find( expr, true, true, false );
    324295        }
    325296
     
    335306                }
    336307
    337                 if ( StructInstType * structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) {
    338                         addAggMembers( structInst, aggrExpr.get(), alt, alt.cost+Cost::safe, "" );
    339                 } else if ( UnionInstType * unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) {
    340                         addAggMembers( unionInst, aggrExpr.get(), alt, alt.cost+Cost::safe, "" );
     308                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) {
     309                        addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" );
     310                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) {
     311                        addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" );
    341312                } // if
    342313        }
    343314
    344315        template< typename StructOrUnionType >
    345         void AlternativeFinder::Finder::addAggMembers( StructOrUnionType * aggInst, Expression * expr, const Alternative& alt, const Cost &newCost, const std::string & name ) {
     316        void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name ) {
    346317                std::list< Declaration* > members;
    347318                aggInst->lookup( name, members );
    348319
    349320                for ( Declaration * decl : members ) {
    350                         if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType* >( decl ) ) {
     321                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( decl ) ) {
    351322                                // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
    352323                                // can't construct in place and use vector::back
    353                                 Alternative newAlt{ alt, new MemberExpr{ dwt, expr->clone() }, newCost };
     324                                Alternative newAlt( new MemberExpr( dwt, expr->clone() ), env, newCost );
    354325                                renameTypes( newAlt.expr );
    355326                                addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
     
    361332        }
    362333
    363         void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression * expr, const Alternative &alt, const Cost &newCost, Expression * member ) {
     334        void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
    364335                if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
    365336                        // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
    366                         auto val = constantExpr->intValue();
     337                        // xxx - this should be improved by memoizing the value of constant exprs
     338                        // during parsing and reusing that information here.
     339                        std::stringstream ss( constantExpr->get_constant()->get_value() );
     340                        int val = 0;
    367341                        std::string tmp;
    368                         if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    369                                 alternatives.push_back( Alternative{
    370                                         alt, new TupleIndexExpr( expr->clone(), val ), newCost } );
     342                        if ( ss >> val && ! (ss >> tmp) ) {
     343                                if ( val >= 0 && (unsigned int)val < tupleType->size() ) {
     344                                        alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
     345                                } // if
    371346                        } // if
     347                } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {
     348                        // xxx - temporary hack until 0/1 are int constants
     349                        if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {
     350                                std::stringstream ss( nameExpr->get_name() );
     351                                int val;
     352                                ss >> val;
     353                                alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
     354                        }
    372355                } // if
    373356        }
    374357
    375         void AlternativeFinder::Finder::postvisit( ApplicationExpr * applicationExpr ) {
    376                 alternatives.push_back( Alternative{ applicationExpr->clone(), env } );
    377         }
    378 
    379         Cost computeConversionCost( Type * actualType, Type * formalType, bool actualIsLvalue,
    380                         const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
     358        void AlternativeFinder::Finder::postvisit( ApplicationExpr *applicationExpr ) {
     359                alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
     360        }
     361
     362        Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
    381363                PRINT(
    382364                        std::cerr << std::endl << "converting ";
     
    388370                        std::cerr << std::endl;
    389371                )
    390                 Cost convCost = conversionCost( actualType, formalType, actualIsLvalue, indexer, env );
     372                Cost convCost = conversionCost( actualType, formalType, indexer, env );
    391373                PRINT(
    392374                        std::cerr << std::endl << "cost is " << convCost << std::endl;
     
    403385
    404386        Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
    405                 Cost convCost = computeConversionCost(
    406                         actualExpr->result, formalType, actualExpr->get_lvalue(), indexer, env );
     387                Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
    407388
    408389                // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion.
     
    432413        Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
    433414                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr );
    434                 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->function->result );
    435                 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->base );
     415                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
     416                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
    436417
    437418                Cost convCost = Cost::zero;
    438                 std::list< DeclarationWithType* >& formals = function->parameters;
     419                std::list< DeclarationWithType* >& formals = function->get_parameters();
    439420                std::list< DeclarationWithType* >::iterator formal = formals.begin();
    440                 std::list< Expression* >& actuals = appExpr->args;
    441 
    442                 for ( Expression*& actualExpr : actuals ) {
    443                         Type * actualType = actualExpr->result;
     421                std::list< Expression* >& actuals = appExpr->get_args();
     422
     423                for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
     424                        Type * actualType = (*actualExpr)->get_result();
    444425                        PRINT(
    445426                                std::cerr << "actual expression:" << std::endl;
    446                                 actualExpr->print( std::cerr, 8 );
     427                                (*actualExpr)->print( std::cerr, 8 );
    447428                                std::cerr << "--- results are" << std::endl;
    448429                                actualType->print( std::cerr, 8 );
    449430                        )
    450431                        if ( formal == formals.end() ) {
    451                                 if ( function->isVarArgs ) {
     432                                if ( function->get_isVarArgs() ) {
    452433                                        convCost.incUnsafe();
    453434                                        PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
    454435                                        // convert reference-typed expressions to value-typed expressions
    455                                         referenceToRvalueConversion( actualExpr, convCost );
     436                                        referenceToRvalueConversion( *actualExpr, convCost );
    456437                                        continue;
    457438                                } else {
     
    459440                                }
    460441                        }
    461                         if ( DefaultArgExpr * def = dynamic_cast< DefaultArgExpr * >( actualExpr ) ) {
    462                                 // default arguments should be free - don't include conversion cost.
    463                                 // Unwrap them here because they are not relevant to the rest of the system.
    464                                 actualExpr = def->expr;
    465                                 ++formal;
    466                                 continue;
    467                         }
    468                         // mark conversion cost to formal and also specialization cost of formal type
    469442                        Type * formalType = (*formal)->get_type();
    470                         convCost += computeExpressionConversionCost( actualExpr, formalType, indexer, alt.env );
    471                         convCost.decSpec( specCost( formalType ) );
     443                        convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
    472444                        ++formal; // can't be in for-loop update because of the continue
    473445                }
     
    476448                }
    477449
    478                 // specialization cost of return types can't be accounted for directly, it disables
    479                 // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    480                 //
    481                 //   forall(otype OS) {
    482                 //     void ?|?(OS&, int);  // with newline
    483                 //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
    484                 //   }
    485 
    486                 // mark type variable and specialization cost of forall clause
    487                 convCost.incVar( function->forall.size() );
    488                 for ( TypeDecl* td : function->forall ) {
    489                         convCost.decSpec( td->assertions.size() );
     450                for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
     451                        convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
    490452                }
    491453
     
    500462                                needAssertions[ *assert ].isUsed = true;
    501463                        }
    502                 }
    503         }
    504 
    505         /// Unique identifier for matching expression resolutions to their requesting expression (located in CandidateFinder.cpp)
    506         extern UniqueId globalResnSlot;
     464///     needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
     465                }
     466        }
     467
     468        static const int recursionLimit = /*10*/ 4;  ///< Limit to depth of recursion satisfaction
     469
     470        void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
     471                for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
     472                        if ( i->second.isUsed ) {
     473                                indexer.addId( i->first );
     474                        }
     475                }
     476        }
     477
     478        template< typename ForwardIterator, typename OutputIterator >
     479        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 ) {
     480                if ( begin == end ) {
     481                        if ( newNeed.empty() ) {
     482                                PRINT(
     483                                        std::cerr << "all assertions satisfied, output alternative: ";
     484                                        newAlt.print( std::cerr );
     485                                        std::cerr << std::endl;
     486                                );
     487                                *out++ = newAlt;
     488                                return;
     489                        } else if ( level >= recursionLimit ) {
     490                                SemanticError( newAlt.expr->location, "Too many recursive assertions" );
     491                        } else {
     492                                AssertionSet newerNeed;
     493                                PRINT(
     494                                        std::cerr << "recursing with new set:" << std::endl;
     495                                        printAssertionSet( newNeed, std::cerr, 8 );
     496                                )
     497                                inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, level+1, indexer, out );
     498                                return;
     499                        }
     500                }
     501
     502                ForwardIterator cur = begin++;
     503                if ( ! cur->second.isUsed ) {
     504                        inferRecursive( begin, end, newAlt, openVars, decls, newNeed, level, indexer, out );
     505                        return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
     506                }
     507                DeclarationWithType *curDecl = cur->first;
     508
     509                PRINT(
     510                        std::cerr << "inferRecursive: assertion is ";
     511                        curDecl->print( std::cerr );
     512                        std::cerr << std::endl;
     513                )
     514                std::list< SymTab::Indexer::IdData > candidates;
     515                decls.lookupId( curDecl->get_name(), candidates );
     516///   if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
     517                for ( const auto & data : candidates ) {
     518                        DeclarationWithType * candidate = data.id;
     519                        PRINT(
     520                                std::cerr << "inferRecursive: candidate is ";
     521                                candidate->print( std::cerr );
     522                                std::cerr << std::endl;
     523                        )
     524
     525                        AssertionSet newHave, newerNeed( newNeed );
     526                        TypeEnvironment newEnv( newAlt.env );
     527                        OpenVarSet newOpenVars( openVars );
     528                        Type *adjType = candidate->get_type()->clone();
     529                        adjustExprType( adjType, newEnv, indexer );
     530                        renameTyVars( adjType );
     531                        PRINT(
     532                                std::cerr << "unifying ";
     533                                curDecl->get_type()->print( std::cerr );
     534                                std::cerr << " with ";
     535                                adjType->print( std::cerr );
     536                                std::cerr << std::endl;
     537                        )
     538                        if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
     539                                PRINT(
     540                                        std::cerr << "success!" << std::endl;
     541                                )
     542                                SymTab::Indexer newDecls( decls );
     543                                addToIndexer( newHave, newDecls );
     544                                Alternative newerAlt( newAlt );
     545                                newerAlt.env = newEnv;
     546                                assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
     547
     548                                // everything with an empty idChain was pulled in by the current assertion.
     549                                // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
     550                                for ( auto & a : newerNeed ) {
     551                                        if ( a.second.idChain.empty() ) {
     552                                                a.second.idChain = cur->second.idChain;
     553                                                a.second.idChain.push_back( curDecl->get_uniqueId() );
     554                                        }
     555                                }
     556
     557                                Expression *varExpr = data.combine( newerAlt.cvtCost );
     558                                delete varExpr->get_result();
     559                                varExpr->set_result( adjType->clone() );
     560                                PRINT(
     561                                        std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
     562                                        curDecl->print( std::cerr );
     563                                        std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
     564                                        candidate->print( std::cerr );
     565                                        std::cerr << std::endl;
     566                                )
     567                                // 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).
     568                                InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
     569                                for ( UniqueId id : cur->second.idChain ) {
     570                                        inferParameters = (*inferParameters)[ id ].inferParams.get();
     571                                }
     572                                // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
     573                                (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
     574                                inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, level, indexer, out );
     575                        } else {
     576                                delete adjType;
     577                        }
     578                }
     579        }
    507580
    508581        template< typename OutputIterator >
    509         void AlternativeFinder::Finder::inferParameters( Alternative &newAlt, OutputIterator out ) {
    510                 // Set need bindings for any unbound assertions
    511                 UniqueId crntResnSlot = 0;  // matching ID for this expression's assertions
    512                 for ( auto& assn : newAlt.need ) {
    513                         // skip already-matched assertions
    514                         if ( assn.info.resnSlot != 0 ) continue;
    515                         // assign slot for expression if needed
    516                         if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
    517                         // fix slot to assertion
    518                         assn.info.resnSlot = crntResnSlot;
    519                 }
    520                 // pair slot to expression
    521                 if ( crntResnSlot != 0 ) { newAlt.expr->resnSlots.push_back( crntResnSlot ); }
    522 
    523                 // add to output list, assertion resolution is deferred
    524                 *out++ = newAlt;
     582        void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
     583//      PRINT(
     584//          std::cerr << "inferParameters: assertions needed are" << std::endl;
     585//          printAll( need, std::cerr, 8 );
     586//          )
     587                SymTab::Indexer decls( indexer );
     588                // PRINT(
     589                //      std::cerr << "============= original indexer" << std::endl;
     590                //      indexer.print( std::cerr );
     591                //      std::cerr << "============= new indexer" << std::endl;
     592                //      decls.print( std::cerr );
     593                // )
     594                addToIndexer( have, decls );
     595                AssertionSet newNeed;
     596                PRINT(
     597                        std::cerr << "env is: " << std::endl;
     598                        newAlt.env.print( std::cerr, 0 );
     599                        std::cerr << std::endl;
     600                )
     601
     602                inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out );
     603//      PRINT(
     604//          std::cerr << "declaration 14 is ";
     605//          Declaration::declFromId
     606//          *out++ = newAlt;
     607//          )
    525608        }
    526609
     
    528611        ConstantExpr* getDefaultValue( Initializer* init ) {
    529612                if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
    530                         if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->value ) ) {
    531                                 return dynamic_cast<ConstantExpr*>( ce->arg );
    532                         } else {
    533                                 return dynamic_cast<ConstantExpr*>( si->value );
     613                        if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->get_value() ) ) {
     614                                return dynamic_cast<ConstantExpr*>( ce->get_arg() );
    534615                        }
    535616                }
     
    578659
    579660                /// Gets the list of exploded alternatives for this pack
    580                 const ExplodedActual& getExpl( const ExplodedArgs_old& args ) const {
     661                const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
    581662                        return args[nextArg-1][explAlt];
    582663                }
     
    602683        /// Instantiates an argument to match a formal, returns false if no results left
    603684        bool instantiateArgument( Type* formalType, Initializer* initializer,
    604                         const ExplodedArgs_old& args, std::vector<ArgPack>& results, std::size_t& genStart,
     685                        const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
    605686                        const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
    606687                if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
     
    792873                                                                indexer ) ) {
    793874                                                        results.emplace_back(
    794                                                                 i, new DefaultArgExpr( cnstExpr ), move(env), move(need), move(have),
     875                                                                i, cnstExpr, move(env), move(need), move(have),
    795876                                                                move(openVars), nextArg, nTuples );
    796877                                                }
     
    863944                }
    864945                // build and validate new alternative
    865                 Alternative newAlt{ appExpr, result.env, result.openVars, result.need, cost };
     946                Alternative newAlt( appExpr, result.env, cost );
    866947                PRINT(
    867948                        std::cerr << "instantiate function success: " << appExpr << std::endl;
     
    869950                        printAssertionSet( result.need, std::cerr, 8 );
    870951                )
    871                 inferParameters( newAlt, out );
     952                inferParameters( result.need, result.have, newAlt, result.openVars, out );
    872953        }
    873954
    874955        template<typename OutputIterator>
    875956        void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
    876                         FunctionType *funcType, const ExplodedArgs_old &args, OutputIterator out ) {
     957                        FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
    877958                OpenVarSet funcOpenVars;
    878959                AssertionSet funcNeed, funcHave;
     
    9841065                funcFinder.findWithAdjustment( untypedExpr->function );
    9851066                // if there are no function alternatives, then proceeding is a waste of time.
    986                 // xxx - findWithAdjustment throws, so this check and others like it shouldn't be necessary.
    9871067                if ( funcFinder.alternatives.empty() ) return;
    9881068
     
    10061086
    10071087                // pre-explode arguments
    1008                 ExplodedArgs_old argExpansions;
     1088                ExplodedArgs argExpansions;
    10091089                argExpansions.reserve( argAlternatives.size() );
    10101090
     
    10121092                        argExpansions.emplace_back();
    10131093                        auto& argE = argExpansions.back();
    1014                         // argE.reserve( arg.alternatives.size() );
     1094                        argE.reserve( arg.alternatives.size() );
    10151095
    10161096                        for ( const Alternative& actual : arg ) {
     
    10981178                                std::cerr << "bindings are:" << std::endl;
    10991179                                withFunc.env.print( std::cerr, 8 );
    1100                                 std::cerr << "cost is: " << withFunc.cost << std::endl;
    11011180                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
    11021181                        )
     
    11141193
    11151194                // function may return struct or union value, in which case we need to add alternatives
    1116                 // for implicit conversions to each of the anonymous members, must happen after findMinCost
     1195                // for implicitconversions to each of the anonymous members, must happen after findMinCost
    11171196                // since anon conversions are never the cheapest expression
    11181197                for ( const Alternative & alt : winners ) {
     
    11371216        bool isLvalue( Expression *expr ) {
    11381217                // xxx - recurse into tuples?
    1139                 return expr->result && ( expr->get_lvalue() || dynamic_cast< ReferenceType * >( expr->result ) );
     1218                return expr->result && ( expr->result->get_lvalue() || dynamic_cast< ReferenceType * >( expr->result ) );
    11401219        }
    11411220
     
    11461225                        if ( isLvalue( alt.expr ) ) {
    11471226                                alternatives.push_back(
    1148                                         Alternative{ alt, new AddressExpr( alt.expr->clone() ), alt.cost } );
     1227                                        Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } );
    11491228                        } // if
    11501229                } // for
     
    11521231
    11531232        void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
    1154                 alternatives.push_back( Alternative{ expr->clone(), env } );
     1233                alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
    11551234        }
    11561235
     
    11971276                AltList candidates;
    11981277                for ( Alternative & alt : finder.alternatives ) {
    1199                         AssertionSet needAssertions( alt.need.begin(), alt.need.end() );
    1200                         AssertionSet haveAssertions;
    1201                         OpenVarSet openVars{ alt.openVars };
     1278                        AssertionSet needAssertions, haveAssertions;
     1279                        OpenVarSet openVars;
    12021280
    12031281                        alt.env.extractOpenVars( openVars );
     
    12141292                        unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
    12151293                                haveAssertions, openVars, indexer );
    1216                         Cost thisCost = castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(),
    1217                                 indexer, alt.env );
     1294                        Cost thisCost = castCost( alt.expr->result, castExpr->result, indexer,
     1295                                alt.env );
    12181296                        PRINT(
    12191297                                std::cerr << "working on cast with result: " << castExpr->result << std::endl;
     
    12271305                                // count one safe conversion for each value that is thrown away
    12281306                                thisCost.incSafe( discardedValues );
    1229                                 Alternative newAlt{
    1230                                         restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ),
    1231                                         alt.env, openVars, needAssertions, alt.cost, alt.cost + thisCost };
    1232                                 inferParameters( newAlt, back_inserter( candidates ) );
     1307                                Alternative newAlt( restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ), alt.env,
     1308                                        alt.cost, thisCost );
     1309                                inferParameters( needAssertions, haveAssertions, newAlt, openVars,
     1310                                        back_inserter( candidates ) );
    12331311                        } // if
    12341312                } // for
     
    12431321
    12441322        void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
    1245                 assertf( castExpr->get_result(), "Implicit virtual cast targets not yet supported." );
     1323                assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
    12461324                AlternativeFinder finder( indexer, env );
    12471325                // don't prune here, since it's guaranteed all alternatives will have the same type
    12481326                finder.findWithoutPrune( castExpr->get_arg() );
    12491327                for ( Alternative & alt : finder.alternatives ) {
    1250                         alternatives.push_back( Alternative{
    1251                                 alt, new VirtualCastExpr{ alt.expr->clone(), castExpr->get_result()->clone() },
    1252                                 alt.cost } );
     1328                        alternatives.push_back( Alternative(
     1329                                new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
     1330                                alt.env, alt.cost ) );
    12531331                }
    12541332        }
     
    12571335                /// Gets name from untyped member expression (member must be NameExpr)
    12581336                const std::string& get_member_name( UntypedMemberExpr *memberExpr ) {
    1259                         if ( dynamic_cast< ConstantExpr * >( memberExpr->get_member() ) ) {
    1260                                 SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
    1261                         } // if
    12621337                        NameExpr * nameExpr = dynamic_cast< NameExpr * >( memberExpr->get_member() );
    12631338                        assert( nameExpr );
     
    12781353                        // find member of the given type
    12791354                        if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
    1280                                 addAggMembers( structInst, aggrExpr, *agg, cost, get_member_name(memberExpr) );
     1355                                addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
    12811356                        } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
    1282                                 addAggMembers( unionInst, aggrExpr, *agg, cost, get_member_name(memberExpr) );
     1357                                addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
    12831358                        } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
    1284                                 addTupleMembers( tupleType, aggrExpr, *agg, cost, memberExpr->get_member() );
     1359                                addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() );
    12851360                        } // if
    12861361                } // for
     
    12881363
    12891364        void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
    1290                 alternatives.push_back( Alternative{ memberExpr->clone(), env } );
     1365                alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
    12911366        }
    12921367
     
    13011376                        // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
    13021377                        // can't construct in place and use vector::back
    1303                         Alternative newAlt{ newExpr, env, OpenVarSet{}, AssertionList{}, Cost::zero, cost };
     1378                        Alternative newAlt( newExpr, env, Cost::zero, cost );
    13041379                        PRINT(
    13051380                                std::cerr << "decl is ";
     
    13191394                // not sufficient to clone here, because variable's type may have changed
    13201395                // since the VariableExpr was originally created.
    1321                 alternatives.push_back( Alternative{ new VariableExpr{ variableExpr->var }, env } );
     1396                alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
    13221397        }
    13231398
    13241399        void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
    1325                 alternatives.push_back( Alternative{ constantExpr->clone(), env } );
     1400                alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
    13261401        }
    13271402
     
    13291404                if ( sizeofExpr->get_isType() ) {
    13301405                        Type * newType = sizeofExpr->get_type()->clone();
    1331                         alternatives.push_back( Alternative{
    1332                                 new SizeofExpr{ resolveTypeof( newType, indexer ) }, env } );
     1406                        alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
    13331407                } else {
    13341408                        // find all alternatives for the argument to sizeof
     
    13441418                        Alternative &choice = winners.front();
    13451419                        referenceToRvalueConversion( choice.expr, choice.cost );
    1346                         alternatives.push_back( Alternative{
    1347                                 choice, new SizeofExpr( choice.expr->clone() ), Cost::zero } );
     1420                        alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
    13481421                } // if
    13491422        }
     
    13521425                if ( alignofExpr->get_isType() ) {
    13531426                        Type * newType = alignofExpr->get_type()->clone();
    1354                         alternatives.push_back( Alternative{
    1355                                 new AlignofExpr{ resolveTypeof( newType, indexer ) }, env } );
     1427                        alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
    13561428                } else {
    13571429                        // find all alternatives for the argument to sizeof
     
    13671439                        Alternative &choice = winners.front();
    13681440                        referenceToRvalueConversion( choice.expr, choice.cost );
    1369                         alternatives.push_back( Alternative{
    1370                                 choice, new AlignofExpr{ choice.expr->clone() }, Cost::zero } );
     1441                        alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
    13711442                } // if
    13721443        }
     
    13781449                for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
    13791450                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
    1380                                 alternatives.push_back( Alternative{
    1381                                         new OffsetofExpr{ aggInst->clone(), dwt }, env } );
     1451                                alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
    13821452                                renameTypes( alternatives.back().expr );
    13831453                        } else {
     
    13981468
    13991469        void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
    1400                 alternatives.push_back( Alternative{ offsetofExpr->clone(), env } );
     1470                alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
    14011471        }
    14021472
    14031473        void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
    1404                 alternatives.push_back( Alternative{ offsetPackExpr->clone(), env } );
    1405         }
    1406 
    1407         void AlternativeFinder::Finder::postvisit( LogicalExpr * logicalExpr ) {
     1474                alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
     1475        }
     1476
     1477        namespace {
     1478                void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
     1479                        // assume no polymorphism
     1480                        // assume no implicit conversions
     1481                        assert( function->get_parameters().size() == 1 );
     1482                        PRINT(
     1483                                std::cerr << "resolvAttr: funcDecl is ";
     1484                                data.id->print( std::cerr );
     1485                                std::cerr << " argType is ";
     1486                                argType->print( std::cerr );
     1487                                std::cerr << std::endl;
     1488                        )
     1489                        const SymTab::Indexer & indexer = finder.get_indexer();
     1490                        AltList & alternatives = finder.get_alternatives();
     1491                        if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
     1492                                Cost cost = Cost::zero;
     1493                                Expression * newExpr = data.combine( cost );
     1494                                alternatives.push_back( Alternative( new AttrExpr( newExpr, argType->clone() ), env, Cost::zero, cost ) );
     1495                                for ( DeclarationWithType * retVal : function->returnVals ) {
     1496                                        alternatives.back().expr->result = retVal->get_type()->clone();
     1497                                } // for
     1498                        } // if
     1499                }
     1500        }
     1501
     1502        void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
     1503                // assume no 'pointer-to-attribute'
     1504                NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
     1505                assert( nameExpr );
     1506                std::list< SymTab::Indexer::IdData > attrList;
     1507                indexer.lookupId( nameExpr->get_name(), attrList );
     1508                if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
     1509                        for ( auto & data : attrList ) {
     1510                                DeclarationWithType * id = data.id;
     1511                                // check if the type is function
     1512                                if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
     1513                                        // assume exactly one parameter
     1514                                        if ( function->get_parameters().size() == 1 ) {
     1515                                                if ( attrExpr->get_isType() ) {
     1516                                                        resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
     1517                                                } else {
     1518                                                        AlternativeFinder finder( indexer, env );
     1519                                                        finder.find( attrExpr->get_expr() );
     1520                                                        for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
     1521                                                                if ( choice->expr->get_result()->size() == 1 ) {
     1522                                                                        resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
     1523                                                                } // fi
     1524                                                        } // for
     1525                                                } // if
     1526                                        } // if
     1527                                } // if
     1528                        } // for
     1529                } else {
     1530                        for ( auto & data : attrList ) {
     1531                                Cost cost = Cost::zero;
     1532                                Expression * newExpr = data.combine( cost );
     1533                                alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
     1534                                renameTypes( alternatives.back().expr );
     1535                        } // for
     1536                } // if
     1537        }
     1538
     1539        void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
    14081540                AlternativeFinder firstFinder( indexer, env );
    14091541                firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
     
    14141546                for ( const Alternative & first : firstFinder.alternatives ) {
    14151547                        for ( const Alternative & second : secondFinder.alternatives ) {
    1416                                 TypeEnvironment compositeEnv{ first.env };
     1548                                TypeEnvironment compositeEnv;
     1549                                compositeEnv.simpleCombine( first.env );
    14171550                                compositeEnv.simpleCombine( second.env );
    1418                                 OpenVarSet openVars{ first.openVars };
    1419                                 mergeOpenVars( openVars, second.openVars );
    1420                                 AssertionSet need;
    1421                                 cloneAll( first.need, need );
    1422                                 cloneAll( second.need, need );
    1423 
    1424                                 LogicalExpr *newExpr = new LogicalExpr{
    1425                                         first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() };
    1426                                 alternatives.push_back( Alternative{
    1427                                         newExpr, std::move(compositeEnv), std::move(openVars),
    1428                                         AssertionList( need.begin(), need.end() ), first.cost + second.cost } );
     1551
     1552                                LogicalExpr *newExpr = new LogicalExpr( first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() );
     1553                                alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
    14291554                        }
    14301555                }
     
    14471572                        for ( const Alternative & second : secondFinder.alternatives ) {
    14481573                                for ( const Alternative & third : thirdFinder.alternatives ) {
    1449                                         TypeEnvironment compositeEnv{ first.env };
     1574                                        TypeEnvironment compositeEnv;
     1575                                        compositeEnv.simpleCombine( first.env );
    14501576                                        compositeEnv.simpleCombine( second.env );
    14511577                                        compositeEnv.simpleCombine( third.env );
    1452                                         OpenVarSet openVars{ first.openVars };
    1453                                         mergeOpenVars( openVars, second.openVars );
    1454                                         mergeOpenVars( openVars, third.openVars );
    1455                                         AssertionSet need;
    1456                                         cloneAll( first.need, need );
    1457                                         cloneAll( second.need, need );
    1458                                         cloneAll( third.need, need );
    1459                                         AssertionSet have;
    14601578
    14611579                                        // unify true and false types, then infer parameters to produce new alternatives
     1580                                        OpenVarSet openVars;
     1581                                        AssertionSet needAssertions, haveAssertions;
     1582                                        Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
    14621583                                        Type* commonType = nullptr;
    1463                                         if ( unify( second.expr->result, third.expr->result, compositeEnv,
    1464                                                         need, have, openVars, indexer, commonType ) ) {
    1465                                                 ConditionalExpr *newExpr = new ConditionalExpr{
    1466                                                         first.expr->clone(), second.expr->clone(), third.expr->clone() };
     1584                                        if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
     1585                                                ConditionalExpr *newExpr = new ConditionalExpr( first.expr->clone(), second.expr->clone(), third.expr->clone() );
    14671586                                                newExpr->result = commonType ? commonType : second.expr->result->clone();
    14681587                                                // convert both options to the conditional result type
    1469                                                 Cost cost = first.cost + second.cost + third.cost;
    1470                                                 cost += computeExpressionConversionCost(
    1471                                                         newExpr->arg2, newExpr->result, indexer, compositeEnv );
    1472                                                 cost += computeExpressionConversionCost(
    1473                                                         newExpr->arg3, newExpr->result, indexer, compositeEnv );
    1474                                                 // output alternative
    1475                                                 Alternative newAlt{
    1476                                                         newExpr, std::move(compositeEnv), std::move(openVars),
    1477                                                         AssertionList( need.begin(), need.end() ), cost };
    1478                                                 inferParameters( newAlt, back_inserter( alternatives ) );
     1588                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
     1589                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
     1590                                                newAlt.expr = newExpr;
     1591                                                inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
    14791592                                        } // if
    14801593                                } // for
     
    14891602                secondFinder.findWithAdjustment( commaExpr->get_arg2() );
    14901603                for ( const Alternative & alt : secondFinder.alternatives ) {
    1491                         alternatives.push_back( Alternative{
    1492                                 alt, new CommaExpr{ newFirstArg->clone(), alt.expr->clone() }, alt.cost } );
     1604                        alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt.expr->clone() ), alt.env, alt.cost ) );
    14931605                } // for
    14941606                delete newFirstArg;
     
    15051617                for ( const Alternative & first : firstFinder.alternatives ) {
    15061618                        for ( const Alternative & second : secondFinder.alternatives ) {
    1507                                 TypeEnvironment compositeEnv{ first.env };
     1619                                TypeEnvironment compositeEnv;
     1620                                compositeEnv.simpleCombine( first.env );
    15081621                                compositeEnv.simpleCombine( second.env );
    1509                                 OpenVarSet openVars{ first.openVars };
    1510                                 mergeOpenVars( openVars, second.openVars );
    1511                                 AssertionSet need;
    1512                                 cloneAll( first.need, need );
    1513                                 cloneAll( second.need, need );
    1514                                 AssertionSet have;
    1515 
     1622                                OpenVarSet openVars;
     1623                                AssertionSet needAssertions, haveAssertions;
     1624                                Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
    15161625                                Type* commonType = nullptr;
    1517                                 if ( unify( first.expr->result, second.expr->result, compositeEnv, need, have,
    1518                                                 openVars, indexer, commonType ) ) {
    1519                                         RangeExpr * newExpr =
    1520                                                 new RangeExpr{ first.expr->clone(), second.expr->clone() };
     1626                                if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
     1627                                        RangeExpr * newExpr = new RangeExpr( first.expr->clone(), second.expr->clone() );
    15211628                                        newExpr->result = commonType ? commonType : first.expr->result->clone();
    1522                                         Alternative newAlt{
    1523                                                 newExpr, std::move(compositeEnv), std::move(openVars),
    1524                                                 AssertionList( need.begin(), need.end() ), first.cost + second.cost };
    1525                                         inferParameters( newAlt, back_inserter( alternatives ) );
     1629                                        newAlt.expr = newExpr;
     1630                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
    15261631                                } // if
    15271632                        } // for
     
    15411646
    15421647                        TypeEnvironment compositeEnv;
    1543                         OpenVarSet openVars;
    1544                         AssertionSet need;
    1545                         for ( const Alternative& alt : alts ) {
    1546                                 compositeEnv.simpleCombine( alt.env );
    1547                                 mergeOpenVars( openVars, alt.openVars );
    1548                                 cloneAll( alt.need, need );
    1549                         }
    1550 
    1551                         alternatives.push_back( Alternative{
    1552                                 new TupleExpr{ exprs }, std::move(compositeEnv), std::move(openVars),
    1553                                 AssertionList( need.begin(), need.end() ), sumCost( alts ) } );
     1648                        simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
     1649                        alternatives.push_back(
     1650                                Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
    15541651                } // for
    15551652        }
    15561653
    15571654        void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
    1558                 alternatives.push_back( Alternative{ tupleExpr->clone(), env } );
     1655                alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
    15591656        }
    15601657
    15611658        void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
    1562                 alternatives.push_back( Alternative{ impCpCtorExpr->clone(), env } );
     1659                alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
    15631660        }
    15641661
     
    15691666                finder.findWithoutPrune( ctorExpr->get_callExpr() );
    15701667                for ( Alternative & alt : finder.alternatives ) {
    1571                         alternatives.push_back( Alternative{
    1572                                 alt, new ConstructorExpr( alt.expr->clone() ), alt.cost } );
     1668                        alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
    15731669                }
    15741670        }
    15751671
    15761672        void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
    1577                 alternatives.push_back( Alternative{ tupleExpr->clone(), env } );
     1673                alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
    15781674        }
    15791675
    15801676        void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
    1581                 alternatives.push_back( Alternative{ tupleAssignExpr->clone(), env } );
     1677                alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
    15821678        }
    15831679
     
    15881684                        // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
    15891685                        UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
    1590                         alternatives.push_back( Alternative{ alt, newUnqExpr, alt.cost } );
     1686                        alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
    15911687                }
    15921688        }
     
    15961692                ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
    15971693                // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
    1598                 alternatives.push_back( Alternative{ newStmtExpr, env } );
     1694                alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
    15991695        }
    16001696
     
    16181714                        for ( Alternative & alt : finder.get_alternatives() ) {
    16191715                                TypeEnvironment newEnv( alt.env );
    1620                                 AssertionSet need;
    1621                                 cloneAll( alt.need, need );
    1622                                 AssertionSet have;
    1623                                 OpenVarSet openVars( alt.openVars );
    1624                                 // xxx - find things in env that don't have a "representative type" and claim
    1625                                 // those are open vars?
     1716                                AssertionSet needAssertions, haveAssertions;
     1717                                OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
    16261718                                PRINT(
    16271719                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    16281720                                )
    1629                                 // It's possible that a cast can throw away some values in a multiply-valued
    1630                                 // expression. (An example is a cast-to-void, which casts from one value to
    1631                                 // zero.)  Figure out the prefix of the subexpression results that are cast
    1632                                 // directly.  The candidate is invalid if it has fewer results than there are
    1633                                 // types to cast to.
     1721                                // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
     1722                                // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
     1723                                // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
     1724                                // to.
    16341725                                int discardedValues = alt.expr->result->size() - toType->size();
    16351726                                if ( discardedValues < 0 ) continue;
    1636                                 // xxx - may need to go into tuple types and extract relevant types and use
    1637                                 // unifyList. Note that currently, this does not allow casting a tuple to an
    1638                                 // atomic type (e.g. (int)([1, 2, 3]))
    1639 
     1727                                // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
     1728                                // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
    16401729                                // unification run for side-effects
    1641                                 unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer );
    1642                                 // xxx - do some inspecting on this line... why isn't result bound to initAlt.type?
    1643 
    1644                                 Cost thisCost = castCost( alt.expr->result, toType, alt.expr->get_lvalue(),
    1645                                         indexer, newEnv );
     1730                                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??
     1731
     1732                                Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
    16461733                                if ( thisCost != Cost::infinity ) {
    16471734                                        // count one safe conversion for each value that is thrown away
    16481735                                        thisCost.incSafe( discardedValues );
    1649                                         Alternative newAlt{
    1650                                                 new InitExpr{
    1651                                                         restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() },
    1652                                                 std::move(newEnv), std::move(openVars),
    1653                                                 AssertionList( need.begin(), need.end() ), alt.cost, thisCost };
    1654                                         inferParameters( newAlt, back_inserter( candidates ) );
     1736                                        Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
     1737                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
    16551738                                }
    16561739                        }
Note: See TracChangeset for help on using the changeset viewer.