source: src/ResolvExpr/AlternativeFinder.cc @ 1a59641

new-env
Last change on this file since 1a59641 was 1a59641, checked in by Aaron Moss <a3moss@…>, 5 years ago

Fix open var handling in BF assn resolution; memory usage reasonable again

  • Property mode set to 100644
File size: 88.5 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// AlternativeFinder.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Sat May 16 23:52:08 2015
11// Last Modified By : Aaron B. Moss
12// Last Modified On : Mon Jun 11 16:40:00 2018
13// Update Count     : 34
14//
15
16#include <algorithm>               // for copy
17#include <cassert>                 // for strict_dynamic_cast, assert, assertf
18#include <cstddef>                 // for size_t
19#include <iostream>                // for operator<<, cerr, ostream, endl
20#include <iterator>                // for back_insert_iterator, back_inserter
21#include <limits>                  // for numeric_limits<int>::max()
22#include <list>                    // for _List_iterator, list, _List_const_...
23#include <map>                     // for _Rb_tree_iterator, map, _Rb_tree_c...
24#include <memory>                  // for allocator_traits<>::value_type
25#include <tuple>                   // for tuple
26#include <utility>                 // for pair
27#include <vector>                  // for vector
28
29#include "Alternative.h"           // for AltList, Alternative
30#include "AlternativeFinder.h"
31#include "Common/SemanticError.h"  // for SemanticError
32#include "Common/utility.h"        // for deleteAll, printAll, CodeLocation
33#include "Cost.h"                  // for Cost, Cost::zero, operator<<, Cost...
34#include "ExplodedActual.h"        // for ExplodedActual
35#include "InitTweak/InitTweak.h"   // for getFunctionName
36#include "RenameVars.h"            // for RenameVars, global_renamer
37#include "ResolveTypeof.h"         // for resolveTypeof
38#include "Resolver.h"              // for resolveStmtExpr
39#include "Common/FilterCombos.h"   // for filterCombos
40#include "Common/GC.h"             // for new_static_root
41#include "SymTab/Indexer.h"        // for Indexer
42#include "SymTab/Mangler.h"        // for Mangler
43#include "SymTab/Validate.h"       // for validateType
44#include "SynTree/Constant.h"      // for Constant
45#include "SynTree/Declaration.h"   // for DeclarationWithType, TypeDecl, Dec...
46#include "SynTree/Expression.h"    // for Expression, CastExpr, NameExpr
47#include "SynTree/Initializer.h"   // for SingleInit, operator<<, Designation
48#include "SynTree/SynTree.h"       // for UniqueId
49#include "SynTree/Type.h"          // for Type, FunctionType, PointerType
50#include "Tuples/Explode.h"        // for explode
51#include "Tuples/Tuples.h"         // for isTtype, handleTupleAssignment
52#include "Unify.h"                 // for unify
53#include "typeops.h"               // for adjustExprType, polyCost, castCost
54
55extern bool resolvep;
56#define PRINT( text ) if ( resolvep ) { text }
57//#define DEBUG_COST
58
59using std::move;
60
61/// copies any copyable type
62template<typename T>
63T copy(const T& x) { return x; }
64
65namespace ResolvExpr {
66        struct AlternativeFinder::Finder : public WithShortCircuiting {
67                Finder( AlternativeFinder & altFinder ) : altFinder( altFinder ), indexer( altFinder.indexer ), alternatives( altFinder.alternatives ), env( altFinder.env ), targetType( altFinder.targetType )  {}
68
69                void previsit( BaseSyntaxNode * ) { visit_children = false; }
70
71                void postvisit( ApplicationExpr * applicationExpr );
72                void postvisit( UntypedExpr * untypedExpr );
73                void postvisit( AddressExpr * addressExpr );
74                void postvisit( LabelAddressExpr * labelExpr );
75                void postvisit( CastExpr * castExpr );
76                void postvisit( VirtualCastExpr * castExpr );
77                void postvisit( UntypedMemberExpr * memberExpr );
78                void postvisit( MemberExpr * memberExpr );
79                void postvisit( NameExpr * variableExpr );
80                void postvisit( VariableExpr * variableExpr );
81                void postvisit( ConstantExpr * constantExpr );
82                void postvisit( SizeofExpr * sizeofExpr );
83                void postvisit( AlignofExpr * alignofExpr );
84                void postvisit( UntypedOffsetofExpr * offsetofExpr );
85                void postvisit( OffsetofExpr * offsetofExpr );
86                void postvisit( OffsetPackExpr * offsetPackExpr );
87                void postvisit( AttrExpr * attrExpr );
88                void postvisit( LogicalExpr * logicalExpr );
89                void postvisit( ConditionalExpr * conditionalExpr );
90                void postvisit( CommaExpr * commaExpr );
91                void postvisit( ImplicitCopyCtorExpr  * impCpCtorExpr );
92                void postvisit( ConstructorExpr  * ctorExpr );
93                void postvisit( RangeExpr  * rangeExpr );
94                void postvisit( UntypedTupleExpr * tupleExpr );
95                void postvisit( TupleExpr * tupleExpr );
96                void postvisit( TupleIndexExpr * tupleExpr );
97                void postvisit( TupleAssignExpr * tupleExpr );
98                void postvisit( UniqueExpr * unqExpr );
99                void postvisit( StmtExpr * stmtExpr );
100                void postvisit( UntypedInitExpr * initExpr );
101                void postvisit( InitExpr * initExpr );
102                void postvisit( DeletedExpr * delExpr );
103                void postvisit( GenericExpr * genExpr );
104
105                /// Adds alternatives for anonymous members
106                void addAnonConversions( const Alternative & alt );
107                /// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
108                template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name );
109                /// Adds alternatives for member expressions where the left side has tuple type
110                void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
111                /// Adds alternatives for offsetof expressions, given the base type and name of the member
112                template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
113                /// Takes a final result and checks if its assertions can be satisfied
114                template<typename OutputIterator>
115                void validateFunctionAlternative( const Alternative &func, ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out );
116                /// Finds matching alternatives for a function, given a set of arguments
117                template<typename OutputIterator>
118                void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
119                /// Checks if assertion parameters match for a new alternative
120                template< typename OutputIterator >
121                void inferParameters( const AssertionSet &need, AssertionSet &have, Alternative &&newAlt, OpenVarSet &openVars, OutputIterator out );
122        private:
123                AlternativeFinder & altFinder;
124                const SymTab::Indexer &indexer;
125                AltList & alternatives;
126                const TypeEnvironment &env;
127                Type *& targetType;
128        };
129
130        Cost sumCost( const AltList &in ) {
131                Cost total = Cost::zero;
132                for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
133                        total += i->cost;
134                }
135                return total;
136        }
137
138        void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) {
139                Indenter indent = { Indenter::tabsize, indentAmt };
140                for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
141                        i->print( os, indent );
142                        os << std::endl;
143                }
144        }
145
146        namespace {
147                void makeExprList( const AltList &in, std::list< Expression* > &out ) {
148                        for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
149                                out.push_back( i->expr->clone() );
150                        }
151                }
152
153                struct PruneStruct {
154                        bool isAmbiguous;
155                        AltList::iterator candidate;
156                        PruneStruct() {}
157                        PruneStruct( AltList::iterator candidate ): isAmbiguous( false ), candidate( candidate ) {}
158                };
159
160                /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations
161                template< typename InputIterator, typename OutputIterator >
162                void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) {
163                        // select the alternatives that have the minimum conversion cost for a particular set of result types
164                        std::map< std::string, PruneStruct > selected;
165                        for ( AltList::iterator candidate = begin; candidate != end; ++candidate ) {
166                                PruneStruct current( candidate );
167                                std::string mangleName;
168                                {
169                                        Type * newType = candidate->expr->get_result()->clone();
170                                        candidate->env.apply( newType );
171                                        mangleName = SymTab::Mangler::mangle( newType );
172                                }
173                                std::map< std::string, PruneStruct >::iterator mapPlace = selected.find( mangleName );
174                                if ( mapPlace != selected.end() ) {
175                                        if ( candidate->cost < mapPlace->second.candidate->cost ) {
176                                                PRINT(
177                                                        std::cerr << "cost " << candidate->cost << " beats " << mapPlace->second.candidate->cost << std::endl;
178                                                )
179                                                selected[ mangleName ] = current;
180                                        } else if ( candidate->cost == mapPlace->second.candidate->cost ) {
181                                                // if one of the candidates contains a deleted identifier, can pick the other, since
182                                                // deleted expressions should not be ambiguous if there is another option that is at least as good
183                                                if ( findDeletedExpr( candidate->expr ) ) {
184                                                        // do nothing
185                                                        PRINT( std::cerr << "candidate is deleted" << std::endl; )
186                                                } else if ( findDeletedExpr( mapPlace->second.candidate->expr ) ) {
187                                                        PRINT( std::cerr << "current is deleted" << std::endl; )
188                                                        selected[ mangleName ] = current;
189                                                } else {
190                                                        PRINT(
191                                                                std::cerr << "marking ambiguous" << std::endl;
192                                                        )
193                                                        mapPlace->second.isAmbiguous = true;
194                                                }
195                                        } else {
196                                                PRINT(
197                                                        std::cerr << "cost " << candidate->cost << " loses to " << mapPlace->second.candidate->cost << std::endl;
198                                                )
199                                        }
200                                } else {
201                                        selected[ mangleName ] = current;
202                                }
203                        }
204
205                        // accept the alternatives that were unambiguous
206                        for ( std::map< std::string, PruneStruct >::iterator target = selected.begin(); target != selected.end(); ++target ) {
207                                if ( ! target->second.isAmbiguous ) {
208                                        Alternative &alt = *target->second.candidate;
209                                        alt.env.applyFree( alt.expr->get_result() );
210                                        *out++ = alt;
211                                }
212                        }
213                }
214
215                void renameTypes( Expression *expr ) {
216                        renameTyVars( expr->result );
217                }
218        } // namespace
219
220        void referenceToRvalueConversion( Expression *& expr, Cost & cost ) {
221                if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
222                        // cast away reference from expr
223                        expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
224                        cost.incReference();
225                }
226        }
227
228        template< typename InputIterator, typename OutputIterator >
229        void AlternativeFinder::findSubExprs( InputIterator begin, InputIterator end, OutputIterator out ) {
230                while ( begin != end ) {
231                        AlternativeFinder finder( indexer, env );
232                        finder.findWithAdjustment( *begin );
233                        // XXX  either this
234                        //Designators::fixDesignations( finder, (*begin++)->get_argName() );
235                        // or XXX this
236                        begin++;
237                        PRINT(
238                                std::cerr << "findSubExprs" << std::endl;
239                                printAlts( finder.alternatives, std::cerr );
240                        )
241                        *out++ = finder;
242                }
243        }
244
245        AlternativeFinder::AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env )
246                : indexer( indexer ), env( env ) {
247        }
248
249        void AlternativeFinder::find( Expression *expr, ResolvMode mode ) {
250                PassVisitor<Finder> finder( *this );
251                expr->accept( finder );
252                if ( mode.failFast && alternatives.empty() ) {
253                        PRINT(
254                                std::cerr << "No reasonable alternatives for expression " << expr << std::endl;
255                        )
256                        SemanticError( expr, "No reasonable alternatives for expression " );
257                }
258                if ( mode.prune ) {
259                        auto oldsize = alternatives.size();
260                        PRINT(
261                                std::cerr << "alternatives before prune:" << std::endl;
262                                printAlts( alternatives, std::cerr );
263                        )
264                        AltList pruned;
265                        pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) );
266                        if ( mode.failFast && pruned.empty() ) {
267                                std::ostringstream stream;
268                                AltList winners;
269                                findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
270                                stream << "Cannot choose between " << winners.size() << " alternatives for expression\n";
271                                expr->print( stream );
272                                stream << " Alternatives are:\n";
273                                printAlts( winners, stream, 1 );
274                                SemanticError( expr->location, stream.str() );
275                        }
276                        alternatives = move(pruned);
277                        PRINT(
278                                std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
279                        )
280                        PRINT(
281                                std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl;
282                        )
283                }
284                // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
285                if ( mode.adjust ) {
286                        for ( Alternative& i : alternatives ) {
287                                adjustExprType( i.expr->result, i.env, indexer );
288                        }
289                }
290
291                // Central location to handle gcc extension keyword, etc. for all expression types.
292                for ( Alternative &iter: alternatives ) {
293                        iter.expr->set_extension( expr->get_extension() );
294                        iter.expr->location = expr->location;
295                } // for
296        }
297
298        void AlternativeFinder::findWithAdjustment( Expression *expr ) {
299                find( expr, ResolvMode::withAdjustment() );
300        }
301
302        void AlternativeFinder::findWithoutPrune( Expression * expr ) {
303                find( expr, ResolvMode::withoutPrune() );
304        }
305
306        void AlternativeFinder::maybeFind( Expression * expr ) {
307                find( expr, ResolvMode::withoutFailFast() );
308        }
309
310        void AlternativeFinder::Finder::addAnonConversions( const Alternative & alt ) {
311                // adds anonymous member interpretations whenever an aggregate value type is seen.
312                // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
313                Expression* aggrExpr = alt.expr->clone();
314                alt.env.apply( aggrExpr->result );
315                Type * aggrType = aggrExpr->result;
316                if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
317                        aggrType = aggrType->stripReferences();
318                        aggrExpr = new CastExpr{ aggrExpr, aggrType->clone() };
319                }
320
321                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) {
322                        addAggMembers( structInst, aggrExpr, alt.cost+Cost::safe, alt.env, "" );
323                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) {
324                        addAggMembers( unionInst, aggrExpr, alt.cost+Cost::safe, alt.env, "" );
325                } // if
326        }
327
328        template< typename StructOrUnionType >
329        void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name ) {
330                std::list< Declaration* > members;
331                aggInst->lookup( name, members );
332
333                for ( Declaration * decl : members ) {
334                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( decl ) ) {
335                                // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
336                                // can't construct in place and use vector::back
337                                Alternative newAlt( new MemberExpr( dwt, expr->clone() ), env, newCost );
338                                renameTypes( newAlt.expr );
339                                addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
340                                alternatives.push_back( std::move(newAlt) );
341                        } else {
342                                assert( false );
343                        }
344                }
345        }
346
347        void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
348                if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
349                        // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
350                        auto val = constantExpr->intValue();
351                        std::string tmp;
352                        if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
353                                alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
354                        } // if
355                } // if
356        }
357
358        void AlternativeFinder::Finder::postvisit( ApplicationExpr *applicationExpr ) {
359                alternatives.push_back( Alternative( applicationExpr, env, Cost::zero ) );
360        }
361
362        Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
363                PRINT(
364                        std::cerr << std::endl << "converting ";
365                        actualType->print( std::cerr, 8 );
366                        std::cerr << std::endl << " to ";
367                        formalType->print( std::cerr, 8 );
368                        std::cerr << std::endl << "environment is: ";
369                        env.print( std::cerr, 8 );
370                        std::cerr << std::endl;
371                )
372                Cost convCost = conversionCost( actualType, formalType, indexer, env );
373                PRINT(
374                        std::cerr << std::endl << "cost is " << convCost << std::endl;
375                )
376                if ( convCost == Cost::infinity ) {
377                        return convCost;
378                }
379                convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) );
380                PRINT(
381                        std::cerr << "cost with polycost is " << convCost << std::endl;
382                )
383                return convCost;
384        }
385
386        Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
387                Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
388
389                // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion.
390                // ignore poly cost for now, since this requires resolution of the cast to infer parameters and this
391                // does not currently work for the reason stated below.
392                Cost tmpCost = convCost;
393                tmpCost.incPoly( -tmpCost.get_polyCost() );
394                if ( tmpCost != Cost::zero ) {
395                        Type *newType = formalType->clone();
396                        env.apply( newType );
397                        actualExpr = new CastExpr( actualExpr, newType );
398                        // xxx - SHOULD be able to resolve this cast, but at the moment pointers are not castable to zero_t, but are implicitly convertible. This is clearly
399                        // inconsistent, once this is fixed it should be possible to resolve the cast.
400                        // xxx - this isn't working, it appears because type1 (the formal type) is seen as widenable, but it shouldn't be, because this makes the conversion from DT* to DT* since commontype(zero_t, DT*) is DT*, rather than just nothing.
401
402                        // AlternativeFinder finder( indexer, env );
403                        // finder.findWithAdjustment( actualExpr );
404                        // assertf( finder.get_alternatives().size() > 0, "Somehow castable expression failed to find alternatives." );
405                        // assertf( finder.get_alternatives().size() == 1, "Somehow got multiple alternatives for known cast expression." );
406                        // Alternative & alt = finder.get_alternatives().front();
407                        // delete actualExpr;
408                        // actualExpr = alt.expr->clone();
409                }
410                return convCost;
411        }
412
413        Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
414                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr );
415                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
416                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
417
418                Cost convCost = Cost::zero;
419                std::list< DeclarationWithType* >& formals = function->get_parameters();
420                std::list< DeclarationWithType* >::iterator formal = formals.begin();
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();
425                        PRINT(
426                                std::cerr << "actual expression:" << std::endl;
427                                (*actualExpr)->print( std::cerr, 8 );
428                                std::cerr << "--- results are" << std::endl;
429                                actualType->print( std::cerr, 8 );
430                        )
431                        if ( formal == formals.end() ) {
432                                if ( function->get_isVarArgs() ) {
433                                        convCost.incUnsafe();
434                                        PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
435                                        // convert reference-typed expressions to value-typed expressions
436                                        referenceToRvalueConversion( *actualExpr, convCost );
437                                        continue;
438                                } else {
439                                        return Cost::infinity;
440                                }
441                        }
442                        if ( DefaultArgExpr * def = dynamic_cast< DefaultArgExpr * >( *actualExpr ) ) {
443                                // default arguments should be free - don't include conversion cost.
444                                // Unwrap them here because they are not relevant to the rest of the system.
445                                *actualExpr = def->expr;
446                                ++formal;
447                                continue;
448                        }
449                        Type * formalType = (*formal)->get_type();
450                        convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
451                        ++formal; // can't be in for-loop update because of the continue
452                }
453                if ( formal != formals.end() ) {
454                        return Cost::infinity;
455                }
456
457                #if 1 // cost of assertions accounted for in function creation
458                for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
459                        convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
460                }
461                #endif
462
463                return convCost;
464        }
465
466        /// Adds type variables to the open variable set and marks their assertions
467        void makeUnifiableVars( Type *type, OpenVarSet &unifiableVars, AssertionSet &needAssertions ) {
468                for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
469                        unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar };
470                        for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->assertions.begin(); assert != (*tyvar)->assertions.end(); ++assert ) {
471                                needAssertions[ *assert ].isUsed = true;
472                        }
473///     needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
474                }
475        }
476
477        static const int recursionLimit = /*10*/ 4;  ///< Limit to depth of recursion satisfaction
478
479        void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
480                for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
481                        if ( i->second.isUsed ) {
482                                indexer.addId( i->first );
483                        }
484                }
485        }
486
487        template< typename ForwardIterator, typename OutputIterator >
488        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 ) {
489                if ( begin == end ) {
490                        if ( newNeed.empty() ) {
491                                PRINT(
492                                        std::cerr << "all assertions satisfied, output alternative: ";
493                                        newAlt.print( std::cerr );
494                                        std::cerr << std::endl;
495                                );
496                                *out++ = newAlt;
497                                return;
498                        } else if ( level >= recursionLimit ) {
499                                SemanticError( newAlt.expr->location, "Too many recursive assertions" );
500                        } else {
501                                AssertionSet newerNeed;
502                                PRINT(
503                                        std::cerr << "recursing with new set:" << std::endl;
504                                        printAssertionSet( newNeed, std::cerr, 8 );
505                                )
506                                inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, level+1, indexer, out );
507                                return;
508                        }
509                }
510
511                ForwardIterator cur = begin++;
512                if ( ! cur->second.isUsed ) {
513                        inferRecursive( begin, end, newAlt, openVars, decls, newNeed, level, indexer, out );
514                        return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
515                }
516                DeclarationWithType *curDecl = cur->first;
517
518                PRINT(
519                        std::cerr << "inferRecursive: assertion is ";
520                        curDecl->print( std::cerr );
521                        std::cerr << std::endl;
522                )
523                std::list< SymTab::Indexer::IdData > candidates;
524                decls.lookupId( curDecl->get_name(), candidates );
525///   if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
526                for ( const auto & data : candidates ) {
527                        DeclarationWithType * candidate = data.id;
528                        PRINT(
529                                std::cerr << "inferRecursive: candidate is ";
530                                candidate->print( std::cerr );
531                                std::cerr << std::endl;
532                        )
533
534                        AssertionSet newHave, newerNeed( newNeed );
535                        TypeEnvironment newEnv( newAlt.env );
536                        OpenVarSet newOpenVars( openVars );
537                        Type *adjType = candidate->get_type()->clone();
538                        adjustExprType( adjType, newEnv, indexer );
539                        renameTyVars( adjType );
540                        PRINT(
541                                std::cerr << "unifying ";
542                                curDecl->get_type()->print( std::cerr );
543                                std::cerr << " with ";
544                                adjType->print( std::cerr );
545                                std::cerr << std::endl;
546                        )
547                        if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
548                                PRINT(
549                                        std::cerr << "success!" << std::endl;
550                                )
551                                SymTab::Indexer newDecls( decls );
552                                addToIndexer( newHave, newDecls );
553                                Alternative newerAlt( newAlt );
554                                newerAlt.env = newEnv;
555                                assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
556
557                                // everything with an empty idChain was pulled in by the current assertion.
558                                // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
559                                for ( auto & a : newerNeed ) {
560                                        if ( a.second.idChain.empty() ) {
561                                                a.second.idChain = cur->second.idChain;
562                                                a.second.idChain.push_back( curDecl->get_uniqueId() );
563                                        }
564                                }
565
566                                Expression *varExpr = data.combine( newerAlt.cvtCost );
567                                varExpr->set_result( adjType->clone() );
568                                PRINT(
569                                        std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
570                                        curDecl->print( std::cerr );
571                                        std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
572                                        candidate->print( std::cerr );
573                                        std::cerr << std::endl;
574                                )
575                                // 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).
576                                InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
577                                for ( UniqueId id : cur->second.idChain ) {
578                                        inferParameters = (*inferParameters)[ id ].inferParams.get();
579                                }
580                               
581                                (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType, curDecl->get_type(), varExpr );
582                                inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, level, indexer, out );
583                        }
584                }
585        }
586
587#if 1
588        namespace {
589                /// Information required to defer resolution of an expression
590                struct AssertionPack {
591                        SymTab::Indexer::IdData cdata;  ///< Satisfying declaration
592                        Type* adjType;                  ///< Satisfying type
593                        TypeEnvironment env;            ///< Post-unification environment
594                        AssertionSet have;              ///< Post-unification have-set
595                        AssertionSet need;              ///< Post-unification need-set
596                        OpenVarSet openVars;            ///< Post-unification open-var set
597
598                        AssertionPack( const SymTab::Indexer::IdData& cdata, Type* adjType, 
599                                        TypeEnvironment&& env, AssertionSet&& have, AssertionSet&& need, 
600                                        OpenVarSet&& openVars ) 
601                                : cdata(cdata), adjType(adjType), env(std::move(env)), have(std::move(have)), 
602                                  need(std::move(need)), openVars(std::move(openVars)) {}
603                       
604                        class iterator {
605                        friend AssertionPack;
606                        public:
607                                const AssertionPack& pack;
608                        private:
609                                AssertionSet::iterator it;
610
611                                iterator(const AssertionPack& p, AssertionSet::iterator i) : pack{p}, it{i} {}
612                        public:
613                                iterator& operator++ () { ++it; return *this; }
614                                iterator operator++ (int) { iterator tmp = *this; ++it; return tmp; }
615                                AssertionSet::value_type& operator* () { return *it; }
616                                AssertionSet::value_type* operator-> () { return it.operator->(); }
617                                bool operator== (const iterator& o) const { return this == &o && it == o.it; }
618                                bool operator!= (const iterator& o) const { return !(*this == o); }
619                        };
620
621                        iterator begin() { return { *this, need.begin() }; }
622                        iterator end() { return { *this, need.end() }; }
623                };
624
625                /// List of deferred assertion resolutions for the same type
626                using DeferList = std::vector<AssertionPack>;
627
628                /// Single deferred item
629                struct DeferElement {
630                        const DeclarationWithType* curDecl;
631                        const AssertionSetValue& assnInfo;
632                        const AssertionPack& match;
633                };
634
635                /// Wrapper for the DeferList of a single assertion resolution
636                struct DeferItem {
637                        DeclarationWithType* curDecl;
638                        AssertionSetValue assnInfo;
639                        DeferList matches;
640
641                        DeferItem(DeclarationWithType* cd, const AssertionSetValue& ai, DeferList&& m )
642                                : curDecl{cd}, assnInfo{ai}, matches(std::move(m)) {}
643
644                        bool empty() const { return matches.empty(); }
645
646                        DeferList::size_type size() const { return matches.size(); }
647
648                        DeferElement operator[] ( unsigned i ) const {
649                                return { curDecl, assnInfo, matches[i] };
650                        }
651                };
652
653                /// Flag for state iteration
654                enum CopyFlag { IterateState };
655
656                /// Intermediate state for assertion resolution
657                struct AssertionResnState {
658                        Alternative alt;                  ///< Alternative being built from
659                        AssertionSet need;                ///< Assertions to find
660                        AssertionSet newNeed;             ///< New assertions found from current assertions
661                        OpenVarSet openVars;              ///< Open variables in current context
662                        std::vector<DeferItem> deferred;  ///< Possible deferred assertion resolutions
663                        SymTab::Indexer& indexer;         ///< Name lookup
664
665                        /// field-wise constructor (some fields defaulted)
666                        AssertionResnState(Alternative&& alt, const AssertionSet& need, 
667                                const OpenVarSet& openVars, SymTab::Indexer& indexer ) 
668                                : alt{std::move(alt)}, need{need}, newNeed{}, openVars{openVars}, deferred{}, 
669                                  indexer{indexer} {}
670                       
671                        /// construct iterated state object from previous state
672                        AssertionResnState(AssertionResnState&& o, CopyFlag) 
673                                : alt{std::move(o.alt)}, need{std::move(o.newNeed)}, newNeed{}, 
674                                  openVars{std::move(o.openVars)}, deferred{}, indexer{o.indexer} {}
675                       
676                        /// copy resn state updated with specified data
677                        AssertionResnState(const AssertionResnState& o, const AssertionSet& need, 
678                                const OpenVarSet& openVars, TypeEnvironment& env )
679                                : alt{o.alt}, need{}, newNeed{o.newNeed}, openVars{openVars}, deferred{},
680                                  indexer{o.indexer} {
681                                newNeed.insert( need.begin(), need.end() );
682                                alt.env = env;
683                        }
684                };
685
686                /// Binds a single assertion from a compatible AssertionPack, updating resolution state
687                /// as appropriate.
688                void bindAssertion( const DeclarationWithType* curDecl, const AssertionSetValue& assnInfo, 
689                                Alternative& alt, AssertionPack& match ) {
690
691                        DeclarationWithType* candidate = match.cdata.id;
692                        assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
693                        for ( auto& a : match.need ) {
694                                if ( a.second.idChain.empty() ) {
695                                        a.second.idChain = assnInfo.idChain;
696                                        a.second.idChain.push_back( curDecl->get_uniqueId() );
697                                }
698                        }
699
700                        Expression* varExpr = match.cdata.combine( alt.cvtCost );
701                        varExpr->result = match.adjType;
702
703                        // follow the current assertion's ID chain to find the correct set of inferred
704                        // parameters to add the candidate o (i.e. the set of inferred parameters belonging
705                        // to the entity which requested the assertion parameter)
706                        InferredParams* inferParams = &alt.expr->inferParams;
707                        for ( UniqueId id : assnInfo.idChain ) {
708                                inferParams = (*inferParams)[ id ].inferParams.get();
709                        }
710
711                        (*inferParams)[ curDecl->get_uniqueId() ] = ParamEntry{
712                                candidate->get_uniqueId(), match.adjType, curDecl->get_type(), varExpr };
713                }
714
715                /// Resolves a single assertion, returning false if no satisfying assertion, binding it
716                /// if there is exactly one satisfying assertion, or adding to the defer-list if there
717                /// is more than one
718                bool resolveAssertion( DeclarationWithType* curDecl, AssertionSetValue& assnInfo, 
719                                AssertionResnState& resn ) {
720                        // skip unused assertions
721                        if ( ! assnInfo.isUsed ) return true;
722
723                        // lookup candidates for this assertion
724                        std::list< SymTab::Indexer::IdData > candidates;
725                        resn.indexer.lookupId( curDecl->name, candidates );
726
727                        // find the ones that unify with the desired type
728                        DeferList matches;
729                        for ( const auto& cdata : candidates ) {
730                                DeclarationWithType* candidate = cdata.id;
731
732                                // build independent unification context for candidate
733                                AssertionSet have, newNeed;
734                                TypeEnvironment newEnv{ resn.alt.env };
735                                OpenVarSet newOpenVars{ resn.openVars };
736                                Type* adjType = candidate->get_type()->clone();
737                                adjustExprType( adjType, newEnv, resn.indexer );
738                                renameTyVars( adjType );
739
740                                if ( unify( curDecl->get_type(), adjType, newEnv, 
741                                                newNeed, have, newOpenVars, resn.indexer ) ) {
742                                        matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have), 
743                                                std::move(newNeed), std::move(newOpenVars) );
744                                }
745                        }
746
747                        // Break if no suitable assertion
748                        if ( matches.empty() ) return false;
749
750                        // Defer if too many suitable assertions
751                        if ( matches.size() > 1 ) {
752                                resn.deferred.emplace_back( curDecl, assnInfo, std::move(matches) );
753                                return true;
754                        }
755
756                        // otherwise bind current match in ongoing scope
757                        AssertionPack& match = matches.front();
758                        addToIndexer( match.have, resn.indexer );
759                        resn.newNeed.insert( match.need.begin(), match.need.end() );
760                        resn.openVars = std::move(match.openVars);
761                        resn.alt.env = std::move(match.env);
762
763                        bindAssertion( curDecl, assnInfo, resn.alt, match );
764                        return true;
765                }
766
767                /// Combo iterator that combines interpretations into an interpretation list, merging
768                /// their environments. Rejects an appended interpretation if the environments cannot
769                /// be merged.
770                class InterpretationEnvMerger {
771                        /// Current list of merged interpretations
772                        std::vector<DeferElement> crnt;
773                        /// Stack of environments, to support backtracking
774                        std::vector<TypeEnvironment> envs;
775                        /// Open variables for environment combination
776                        std::vector<OpenVarSet> varSets;
777                        /// Indexer to use for environment merges
778                        const SymTab::Indexer& indexer;
779                public:
780                        /// The merged environment/open variables and the list of interpretations
781                        struct OutType {
782                                TypeEnvironment env;
783                                OpenVarSet openVars;
784                                std::vector<DeferElement> assns;
785
786                                OutType( const TypeEnvironment& env, const OpenVarSet& openVars, 
787                                        const std::vector<DeferElement>& assns )
788                                        : env(env), openVars(openVars), assns(assns) {}
789                        };
790
791                        InterpretationEnvMerger( const TypeEnvironment& env, const OpenVarSet& openVars, 
792                                const SymTab::Indexer& indexer ) : crnt{}, envs{}, varSets{}, indexer{indexer} {
793                                envs.push_back( env );
794                                varSets.push_back( openVars );
795                        }
796
797                        ComboResult append( DeferElement i ) {
798                                TypeEnvironment env = envs.back();
799                                OpenVarSet openVars = varSets.back();
800                                mergeOpenVars( openVars, i.match.openVars );
801
802                                if ( ! env.combine( i.match.env, openVars, indexer ) )
803                                        return ComboResult::REJECT_THIS;
804                               
805                                crnt.push_back( i );
806                                envs.push_back( env );
807                                varSets.push_back( openVars );
808                                return ComboResult::ACCEPT;
809                        }
810
811                        void backtrack() {
812                                crnt.pop_back();
813                                envs.pop_back();
814                                varSets.pop_back();
815                        }
816
817                        OutType finalize() { return { envs.back(), varSets.back(), crnt }; }
818                };
819        }
820#endif
821
822        template< typename OutputIterator >
823        void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, Alternative &&newAlt, OpenVarSet &openVars, OutputIterator out ) {
824//      PRINT(
825//          std::cerr << "inferParameters: assertions needed are" << std::endl;
826//          printAll( need, std::cerr, 8 );
827//          )
828                SymTab::Indexer decls( indexer );
829                // PRINT(
830                //      std::cerr << "============= original indexer" << std::endl;
831                //      indexer.print( std::cerr );
832                //      std::cerr << "============= new indexer" << std::endl;
833                //      decls.print( std::cerr );
834                // )
835                addToIndexer( have, decls );
836#if 1
837                using ResnList = std::vector<AssertionResnState>;
838                ResnList resns{ AssertionResnState{ std::move(newAlt), need, openVars, decls } };
839                ResnList new_resns{};
840
841                // resolve assertions in breadth-first-order up to a limited number of levels deep
842                for ( int level = 0; level < recursionLimit; ++level ) {
843                        // scan over all mutually-compatible resolutions
844                        for ( auto& resn : resns ) {
845                                // make initial pass at matching assertions
846                                for ( auto& assn : resn.need ) {
847                                        if ( ! resolveAssertion( assn.first, assn.second, resn ) ) {
848                                                // fail early if any assertion fails to resolve
849                                                goto nextResn;
850                                        }
851                                }
852
853                                if ( ! resn.deferred.empty() ) {
854                                        // resolve deferred assertions by mutual compatibility
855
856                                        std::vector<InterpretationEnvMerger::OutType> compatible = filterCombos( 
857                                                resn.deferred, 
858                                                InterpretationEnvMerger{ resn.alt.env, resn.openVars, resn.indexer } );
859                                       
860                                        for ( auto& compat : compatible ) {
861                                                AssertionResnState new_resn = resn;
862
863                                                // add compatible assertions to new resolution state
864                                                for ( DeferElement el : compat.assns ) {
865                                                        AssertionPack match = el.match;
866                                                        addToIndexer( match.have, new_resn.indexer );
867                                                        resn.newNeed.insert( match.need.begin(), match.need.end() );
868                                                       
869                                                        bindAssertion( el.curDecl, el.assnInfo, new_resn.alt, match );
870                                                }
871
872                                                // set mutual environment into resolution state
873                                                new_resn.alt.env = std::move(compat.env);
874                                                new_resn.openVars = std::move(compat.openVars);
875
876                                                // add successful match or push back next state
877                                                if ( new_resn.newNeed.empty() ) {
878                                                        *out++ = new_resn.alt;
879                                                } else {
880                                                        new_resns.emplace_back( std::move(new_resn), IterateState );
881                                                }
882                                        }
883                                } else {
884                                        // add successful match or push back next state
885                                        if ( resn.newNeed.empty() ) {
886                                                *out++ = resn.alt;
887                                        } else {
888                                                new_resns.emplace_back( std::move(resn), IterateState );
889                                        }
890                                }
891                        nextResn:; }
892                       
893                        // finish or reset for next round
894                        if ( new_resns.empty() ) return;
895                        resns.swap( new_resns );
896                        new_resns.clear();
897                }
898                // if reaches here, exceeded recursion limit
899                SemanticError( newAlt.expr->location, "Too many recursive assertions" );
900
901#else           
902                AssertionSet newNeed;
903                PRINT(
904                        std::cerr << "env is: " << std::endl;
905                        newAlt.env.print( std::cerr, 0 );
906                        std::cerr << std::endl;
907                )
908
909                inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out );
910//      PRINT(
911//          std::cerr << "declaration 14 is ";
912//          Declaration::declFromId
913//          *out++ = newAlt;
914//          )
915#endif
916        }
917
918        /// Gets a default value from an initializer, nullptr if not present
919        ConstantExpr* getDefaultValue( Initializer* init ) {
920                if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
921                        if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->value ) ) {
922                                return dynamic_cast<ConstantExpr*>( ce->arg );
923                        } else {
924                                return dynamic_cast<ConstantExpr*>( si->value );
925                        }
926                }
927                return nullptr;
928        }
929
930        /// State to iteratively build a match of parameter expressions to arguments
931        struct ArgPack {
932                std::size_t parent;                ///< Index of parent pack
933                Expression* expr;                  ///< The argument stored here
934                Cost cost;                         ///< The cost of this argument
935                TypeEnvironment env;               ///< Environment for this pack
936                AssertionSet need;                 ///< Assertions outstanding for this pack
937                AssertionSet have;                 ///< Assertions found for this pack
938                OpenVarSet openVars;               ///< Open variables for this pack
939                unsigned nextArg;                  ///< Index of next argument in arguments list
940                unsigned tupleStart;               ///< Number of tuples that start at this index
941                unsigned nextExpl;                 ///< Index of next exploded element
942                unsigned explAlt;                  ///< Index of alternative for nextExpl > 0
943
944                ArgPack()
945                        : parent(0), expr(nullptr), cost(Cost::zero), env(), need(), have(), openVars(), 
946                          nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
947
948                ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
949                                const OpenVarSet& openVars, Cost initCost = Cost::zero)
950                        : parent(0), expr(nullptr), cost(initCost), env(env), need(need), have(have),
951                          openVars(openVars), nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
952
953                ArgPack(std::size_t parent, Expression* expr, TypeEnvironment&& env, AssertionSet&& need,
954                                AssertionSet&& have, OpenVarSet&& openVars, unsigned nextArg,
955                                unsigned tupleStart = 0, Cost cost = Cost::zero, unsigned nextExpl = 0,
956                                unsigned explAlt = 0 )
957                        : parent(parent), expr(expr), cost(cost), env(move(env)), need(move(need)),
958                          have(move(have)), openVars(move(openVars)), nextArg(nextArg), tupleStart(tupleStart),
959                          nextExpl(nextExpl), explAlt(explAlt) {}
960
961                ArgPack(const ArgPack& o, TypeEnvironment&& env, AssertionSet&& need, AssertionSet&& have,
962                                OpenVarSet&& openVars, unsigned nextArg, Cost added )
963                        : parent(o.parent), expr(o.expr), cost(o.cost + added), env(move(env)), 
964                          need(move(need)), have(move(have)), openVars(move(openVars)), nextArg(nextArg), 
965                          tupleStart(o.tupleStart), nextExpl(0), explAlt(0) {}
966
967                /// true iff this pack is in the middle of an exploded argument
968                bool hasExpl() const { return nextExpl > 0; }
969
970                /// Gets the list of exploded alternatives for this pack
971                const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
972                        return args[nextArg-1][explAlt];
973                }
974
975                /// Ends a tuple expression, consolidating the appropriate actuals
976                void endTuple( const std::vector<ArgPack>& packs ) {
977                        // add all expressions in tuple to list, summing cost
978                        std::list<Expression*> exprs;
979                        const ArgPack* pack = this;
980                        if ( expr ) { exprs.push_front( expr ); }
981                        while ( pack->tupleStart == 0 ) {
982                                pack = &packs[pack->parent];
983                                exprs.push_front( pack->expr );
984                                cost += pack->cost;
985                        }
986                        // reset pack to appropriate tuple
987                        expr = new TupleExpr{ exprs };
988                        tupleStart = pack->tupleStart - 1;
989                        parent = pack->parent;
990                }
991        };
992
993        /// Instantiates an argument to match a formal, returns false if no results left
994        bool instantiateArgument( Type* formalType, Initializer* initializer,
995                        const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
996                        const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
997                if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
998                        // formalType is a TupleType - group actuals into a TupleExpr
999                        ++nTuples;
1000                        for ( Type* type : *tupleType ) {
1001                                // xxx - dropping initializer changes behaviour from previous, but seems correct
1002                                // ^^^ need to handle the case where a tuple has a default argument
1003                                if ( ! instantiateArgument(
1004                                                type, nullptr, args, results, genStart, indexer, nTuples ) )
1005                                        return false;
1006                                nTuples = 0;
1007                        }
1008                        // re-consititute tuples for final generation
1009                        for ( auto i = genStart; i < results.size(); ++i ) {
1010                                results[i].endTuple( results );
1011                        }
1012                        return true;
1013                } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
1014                        // formalType is a ttype, consumes all remaining arguments
1015                        // xxx - mixing default arguments with variadic??
1016
1017                        // completed tuples; will be spliced to end of results to finish
1018                        std::vector<ArgPack> finalResults{};
1019
1020                        // iterate until all results completed
1021                        std::size_t genEnd;
1022                        ++nTuples;
1023                        do {
1024                                genEnd = results.size();
1025
1026                                // add another argument to results
1027                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
1028                                        auto nextArg = results[i].nextArg;
1029
1030                                        // use next element of exploded tuple if present
1031                                        if ( results[i].hasExpl() ) {
1032                                                const ExplodedActual& expl = results[i].getExpl( args );
1033
1034                                                unsigned nextExpl = results[i].nextExpl + 1;
1035                                                if ( nextExpl == expl.exprs.size() ) {
1036                                                        nextExpl = 0;
1037                                                }
1038
1039                                                results.emplace_back(
1040                                                        i, expl.exprs[results[i].nextExpl], copy(results[i].env),
1041                                                        copy(results[i].need), copy(results[i].have),
1042                                                        copy(results[i].openVars), nextArg, nTuples, Cost::zero, nextExpl,
1043                                                        results[i].explAlt );
1044
1045                                                continue;
1046                                        }
1047
1048                                        // finish result when out of arguments
1049                                        if ( nextArg >= args.size() ) {
1050                                                ArgPack newResult{
1051                                                        results[i].env, results[i].need, results[i].have,
1052                                                        results[i].openVars };
1053                                                newResult.nextArg = nextArg;
1054                                                Type* argType;
1055
1056                                                if ( nTuples > 0 || ! results[i].expr ) {
1057                                                        // first iteration or no expression to clone,
1058                                                        // push empty tuple expression
1059                                                        newResult.parent = i;
1060                                                        std::list<Expression*> emptyList;
1061                                                        newResult.expr = new TupleExpr{ emptyList };
1062                                                        argType = newResult.expr->get_result();
1063                                                } else {
1064                                                        // clone result to collect tuple
1065                                                        newResult.parent = results[i].parent;
1066                                                        newResult.cost = results[i].cost;
1067                                                        newResult.tupleStart = results[i].tupleStart;
1068                                                        newResult.expr = results[i].expr;
1069                                                        argType = newResult.expr->get_result();
1070
1071                                                        if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
1072                                                                // the case where a ttype value is passed directly is special,
1073                                                                // e.g. for argument forwarding purposes
1074                                                                // xxx - what if passing multiple arguments, last of which is
1075                                                                //       ttype?
1076                                                                // xxx - what would happen if unify was changed so that unifying
1077                                                                //       tuple
1078                                                                // types flattened both before unifying lists? then pass in
1079                                                                // TupleType (ttype) below.
1080                                                                --newResult.tupleStart;
1081                                                        } else {
1082                                                                // collapse leftover arguments into tuple
1083                                                                newResult.endTuple( results );
1084                                                                argType = newResult.expr->get_result();
1085                                                        }
1086                                                }
1087
1088                                                // check unification for ttype before adding to final
1089                                                if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have,
1090                                                                newResult.openVars, indexer ) ) {
1091                                                        finalResults.push_back( move(newResult) );
1092                                                }
1093
1094                                                continue;
1095                                        }
1096
1097                                        // add each possible next argument
1098                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1099                                                const ExplodedActual& expl = args[nextArg][j];
1100
1101                                                // fresh copies of parent parameters for this iteration
1102                                                TypeEnvironment env = results[i].env;
1103                                                OpenVarSet openVars = results[i].openVars;
1104
1105                                                env.addActual( expl.env, openVars );
1106
1107                                                // skip empty tuple arguments by (near-)cloning parent into next gen
1108                                                if ( expl.exprs.empty() ) {
1109                                                        results.emplace_back(
1110                                                                results[i], move(env), copy(results[i].need),
1111                                                                copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
1112
1113                                                        continue;
1114                                                }
1115
1116                                                // add new result
1117                                                results.emplace_back(
1118                                                        i, expl.exprs.front(), move(env), copy(results[i].need),
1119                                                        copy(results[i].have), move(openVars), nextArg + 1,
1120                                                        nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1121                                        }
1122                                }
1123
1124                                // reset for next round
1125                                genStart = genEnd;
1126                                nTuples = 0;
1127                        } while ( genEnd != results.size() );
1128
1129                        // splice final results onto results
1130                        for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
1131                                results.push_back( move(finalResults[i]) );
1132                        }
1133                        return ! finalResults.empty();
1134                }
1135
1136                // iterate each current subresult
1137                std::size_t genEnd = results.size();
1138                for ( std::size_t i = genStart; i < genEnd; ++i ) {
1139                        auto nextArg = results[i].nextArg;
1140
1141                        // use remainder of exploded tuple if present
1142                        if ( results[i].hasExpl() ) {
1143                                const ExplodedActual& expl = results[i].getExpl( args );
1144                                Expression* expr = expl.exprs[results[i].nextExpl];
1145
1146                                TypeEnvironment env = results[i].env;
1147                                AssertionSet need = results[i].need, have = results[i].have;
1148                                OpenVarSet openVars = results[i].openVars;
1149
1150                                Type* actualType = expr->get_result();
1151
1152                                PRINT(
1153                                        std::cerr << "formal type is ";
1154                                        formalType->print( std::cerr );
1155                                        std::cerr << std::endl << "actual type is ";
1156                                        actualType->print( std::cerr );
1157                                        std::cerr << std::endl;
1158                                )
1159
1160                                if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
1161                                        unsigned nextExpl = results[i].nextExpl + 1;
1162                                        if ( nextExpl == expl.exprs.size() ) {
1163                                                nextExpl = 0;
1164                                        }
1165
1166                                        results.emplace_back(
1167                                                i, expr, move(env), move(need), move(have), move(openVars), nextArg,
1168                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
1169                                }
1170
1171                                continue;
1172                        }
1173
1174                        // use default initializers if out of arguments
1175                        if ( nextArg >= args.size() ) {
1176                                if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
1177                                        if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
1178                                                TypeEnvironment env = results[i].env;
1179                                                AssertionSet need = results[i].need, have = results[i].have;
1180                                                OpenVarSet openVars = results[i].openVars;
1181
1182                                                if ( unify( formalType, cnst->get_type(), env, need, have, openVars,
1183                                                                indexer ) ) {
1184                                                        results.emplace_back(
1185                                                                i, new DefaultArgExpr( cnstExpr ), move(env), move(need), move(have),
1186                                                                move(openVars), nextArg, nTuples );
1187                                                }
1188                                        }
1189                                }
1190
1191                                continue;
1192                        }
1193
1194                        // Check each possible next argument
1195                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1196                                const ExplodedActual& expl = args[nextArg][j];
1197
1198                                // fresh copies of parent parameters for this iteration
1199                                TypeEnvironment env = results[i].env;
1200                                AssertionSet need = results[i].need, have = results[i].have;
1201                                OpenVarSet openVars = results[i].openVars;
1202
1203                                env.addActual( expl.env, openVars );
1204
1205                                // skip empty tuple arguments by (near-)cloning parent into next gen
1206                                if ( expl.exprs.empty() ) {
1207                                        results.emplace_back(
1208                                                results[i], move(env), move(need), move(have), move(openVars),
1209                                                nextArg + 1, expl.cost );
1210
1211                                        continue;
1212                                }
1213
1214                                // consider only first exploded actual
1215                                Expression* expr = expl.exprs.front();
1216                                Type* actualType = expr->result->clone();
1217
1218                                PRINT(
1219                                        std::cerr << "formal type is ";
1220                                        formalType->print( std::cerr );
1221                                        std::cerr << std::endl << "actual type is ";
1222                                        actualType->print( std::cerr );
1223                                        std::cerr << std::endl;
1224                                )
1225
1226                                // attempt to unify types
1227                                if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
1228                                        // add new result
1229                                        results.emplace_back(
1230                                                i, expr, move(env), move(need), move(have), move(openVars), nextArg + 1,
1231                                                nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1232                                }
1233                        }
1234                }
1235
1236                // reset for next parameter
1237                genStart = genEnd;
1238
1239                return genEnd != results.size();
1240        }
1241
1242#if !1
1243        namespace {
1244
1245                struct CountSpecs : public WithVisitorRef<CountSpecs>, WithShortCircuiting {
1246
1247                        void postvisit(PointerType*) {
1248                                // mark specialization of base type
1249                                if ( count >= 0 ) ++count;
1250                        }
1251
1252                        void postvisit(ArrayType*) {
1253                                // mark specialization of base type
1254                                if ( count >= 0 ) ++count;
1255                        }
1256
1257                        void postvisit(ReferenceType*) {
1258                                // mark specialization of base type -- xxx maybe not?
1259                                if ( count >= 0 ) ++count;
1260                        }
1261
1262                private:
1263                        // takes minimum non-negative count over parameter/return list
1264                        void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {
1265                                for ( DeclarationWithType* dwt : dwts ) {
1266                                        count = -1;
1267                                        maybeAccept( dwt->get_type(), *visitor );
1268                                        if ( count != -1 && count < mincount ) mincount = count;
1269                                }
1270                        }
1271
1272                public:
1273                        void previsit(FunctionType*) {
1274                                // override default child visiting behaviour
1275                                visit_children = false;
1276                        }
1277
1278                        void postvisit(FunctionType* fty) {
1279                                // take minimal set value of count over ->returnVals and ->parameters
1280                                int mincount = std::numeric_limits<int>::max();
1281                                takeminover( mincount, fty->parameters );
1282                                takeminover( mincount, fty->returnVals );
1283                                // add another level to mincount if set
1284                                count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
1285                        }
1286
1287                private:
1288                        // returns minimum non-negative count + 1 over type parameters (-1 if none such)
1289                        int minover( std::list<Expression*>& parms ) {
1290                                int mincount = std::numeric_limits<int>::max();
1291                                for ( Expression* parm : parms ) {
1292                                        count = -1;
1293                                        maybeAccept( parm->get_result(), *visitor );
1294                                        if ( count != -1 && count < mincount ) mincount = count;
1295                                }
1296                                return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
1297                        }
1298                       
1299                public:
1300                        void previsit(StructInstType*) {
1301                                // override default child behaviour
1302                                visit_children = false;
1303                        }
1304
1305                        void postvisit(StructInstType* sity) {
1306                                // look for polymorphic parameters
1307                                count = minover( sity->parameters );
1308                        }
1309
1310                        void previsit(UnionInstType*) {
1311                                // override default child behaviour
1312                                visit_children = false;
1313                        }
1314
1315                        void postvisit(UnionInstType* uity) {
1316                                // look for polymorphic parameters
1317                                count = minover( uity->parameters );
1318                        }
1319
1320                        void postvisit(TypeInstType*) {
1321                                // note polymorphic type (which may be specialized)
1322                                // xxx - maybe account for open/closed type variables
1323                                count = 0;
1324                        }
1325
1326                        void previsit(TupleType*) {
1327                                // override default child behaviour
1328                                visit_children = false;
1329                        }
1330
1331                        void postvisit(TupleType* tty) {
1332                                // take minimum non-negative count
1333                                int mincount = std::numeric_limits<int>::max();
1334                                for ( Type* ty : tty->types ) {
1335                                        count = -1;
1336                                        maybeAccept( ty, *visitor );
1337                                        if ( count != -1 && count < mincount ) mincount = count;
1338                                }
1339                                // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
1340                                count = mincount < std::numeric_limits<int>::max() ? mincount + 1: -1;
1341                        }
1342
1343                        int get_count() const { return count >= 0 ? count : 0; }
1344                private:
1345                        int count = -1;
1346                };
1347
1348                /// Counts the specializations in the types in a function parameter or return list
1349                int countSpecs( std::list<DeclarationWithType*>& dwts ) {
1350                        int k = 0;
1351                        for ( DeclarationWithType* dwt : dwts ) {
1352                                PassVisitor<CountSpecs> counter;
1353                                maybeAccept( dwt->get_type(), *counter.pass.visitor );
1354                                k += counter.pass.get_count();
1355                        }
1356                        return k;
1357                }
1358
1359                /// Calculates the inherent costs in a function declaration; varCost for the number of
1360                /// type variables and specCost for type assertions, as well as PolyType specializations
1361                /// in the parameter and return lists.
1362                Cost declCost( FunctionType* funcType ) {
1363                        Cost k = Cost::zero;
1364
1365                        // add cost of type variables
1366                        k.incVar( funcType->forall.size() );
1367
1368                        // subtract cost of type assertions
1369                        for ( TypeDecl* td : funcType->forall ) {
1370                                k.decSpec( td->assertions.size() );
1371                        }
1372
1373                        // count specialized polymorphic types in parameter/return lists
1374                        k.decSpec( countSpecs( funcType->parameters ) );
1375                        k.decSpec( countSpecs( funcType->returnVals ) );
1376
1377                        return k;
1378                }
1379        }
1380#endif
1381
1382        template<typename OutputIterator>
1383        void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func, 
1384                        ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out ) {
1385                ApplicationExpr *appExpr = new ApplicationExpr( func.expr );
1386                // sum cost and accumulate actuals
1387                std::list<Expression*>& args = appExpr->args;
1388                Cost cost = func.cost;
1389                const ArgPack* pack = &result;
1390                while ( pack->expr ) {
1391                        args.push_front( pack->expr );
1392                        cost += pack->cost;
1393                        pack = &results[pack->parent];
1394                }
1395                // build and validate new alternative
1396                Alternative newAlt( appExpr, result.env, cost );
1397                PRINT(
1398                        std::cerr << "instantiate function success: " << appExpr << std::endl;
1399                        std::cerr << "need assertions:" << std::endl;
1400                        printAssertionSet( result.need, std::cerr, 8 );
1401                )
1402                inferParameters( result.need, result.have, std::move(newAlt), result.openVars, out );
1403        }
1404
1405        template<typename OutputIterator>
1406        void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
1407                        FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
1408                OpenVarSet funcOpenVars;
1409                AssertionSet funcNeed, funcHave;
1410                TypeEnvironment funcEnv( func.env );
1411                makeUnifiableVars( funcType, funcOpenVars, funcNeed );
1412                // add all type variables as open variables now so that those not used in the parameter
1413                // list are still considered open.
1414                funcEnv.add( funcType->forall );
1415
1416                if ( targetType && ! targetType->isVoid() && ! funcType->returnVals.empty() ) {
1417                        // attempt to narrow based on expected target type
1418                        Type * returnType = funcType->returnVals.front()->get_type();
1419                        if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
1420                                        indexer ) ) {
1421                                // unification failed, don't pursue this function alternative
1422                                return;
1423                        }
1424                }
1425
1426                // calculate declaration cost of function (+vars-spec)
1427#if !1
1428                Cost funcCost = declCost( funcType );
1429#else
1430                Cost funcCost = Cost::zero;
1431#endif
1432
1433                // iteratively build matches, one parameter at a time
1434                std::vector<ArgPack> results;
1435                results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars, funcCost } );
1436                std::size_t genStart = 0;
1437
1438                for ( DeclarationWithType* formal : funcType->parameters ) {
1439                        ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
1440                        if ( ! instantiateArgument(
1441                                        obj->type, obj->init, args, results, genStart, indexer ) )
1442                                return;
1443                }
1444
1445                if ( funcType->get_isVarArgs() ) {
1446                        // append any unused arguments to vararg pack
1447                        std::size_t genEnd;
1448                        do {
1449                                genEnd = results.size();
1450
1451                                // iterate results
1452                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
1453                                        auto nextArg = results[i].nextArg;
1454
1455                                        // use remainder of exploded tuple if present
1456                                        if ( results[i].hasExpl() ) {
1457                                                const ExplodedActual& expl = results[i].getExpl( args );
1458
1459                                                unsigned nextExpl = results[i].nextExpl + 1;
1460                                                if ( nextExpl == expl.exprs.size() ) {
1461                                                        nextExpl = 0;
1462                                                }
1463
1464                                                results.emplace_back(
1465                                                        i, expl.exprs[results[i].nextExpl], copy(results[i].env),
1466                                                        copy(results[i].need), copy(results[i].have),
1467                                                        copy(results[i].openVars), nextArg, 0, Cost::zero, nextExpl,
1468                                                        results[i].explAlt );
1469
1470                                                continue;
1471                                        }
1472
1473                                        // finish result when out of arguments
1474                                        if ( nextArg >= args.size() ) {
1475                                                validateFunctionAlternative( func, results[i], results, out );
1476
1477                                                continue;
1478                                        }
1479
1480                                        // add each possible next argument
1481                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1482                                                const ExplodedActual& expl = args[nextArg][j];
1483
1484                                                // fresh copies of parent parameters for this iteration
1485                                                TypeEnvironment env = results[i].env;
1486                                                OpenVarSet openVars = results[i].openVars;
1487
1488                                                env.addActual( expl.env, openVars );
1489
1490                                                // skip empty tuple arguments by (near-)cloning parent into next gen
1491                                                if ( expl.exprs.empty() ) {
1492                                                        results.emplace_back(
1493                                                                results[i], move(env), copy(results[i].need),
1494                                                                copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
1495
1496                                                        continue;
1497                                                }
1498
1499                                                // add new result
1500                                                results.emplace_back(
1501                                                        i, expl.exprs.front(), move(env), copy(results[i].need),
1502                                                        copy(results[i].have), move(openVars), nextArg + 1, 0,
1503                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1504                                        }
1505                                }
1506
1507                                genStart = genEnd;
1508                        } while ( genEnd != results.size() );
1509                } else {
1510                        // filter out results that don't use all the arguments
1511                        for ( std::size_t i = genStart; i < results.size(); ++i ) {
1512                                ArgPack& result = results[i];
1513                                if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
1514                                        validateFunctionAlternative( func, result, results, out );
1515                                }
1516                        }
1517                }
1518        }
1519
1520        void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
1521                AlternativeFinder funcFinder( indexer, env );
1522                funcFinder.findWithAdjustment( untypedExpr->function );
1523                // if there are no function alternatives, then proceeding is a waste of time.
1524                // xxx - findWithAdjustment throws, so this check and others like it shouldn't be necessary.
1525                if ( funcFinder.alternatives.empty() ) return;
1526
1527                std::vector< AlternativeFinder > argAlternatives;
1528                altFinder.findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
1529                        back_inserter( argAlternatives ) );
1530
1531                // take care of possible tuple assignments
1532                // if not tuple assignment, assignment is taken care of as a normal function call
1533                Tuples::handleTupleAssignment( altFinder, untypedExpr, argAlternatives );
1534
1535                // find function operators
1536                static auto *opExpr = new_static_root<NameExpr>( "?()" );
1537                AlternativeFinder funcOpFinder( indexer, env );
1538                // it's ok if there aren't any defined function ops
1539                funcOpFinder.maybeFind( opExpr );
1540                PRINT(
1541                        std::cerr << "known function ops:" << std::endl;
1542                        printAlts( funcOpFinder.alternatives, std::cerr, 1 );
1543                )
1544
1545                // pre-explode arguments
1546                ExplodedArgs argExpansions;
1547                argExpansions.reserve( argAlternatives.size() );
1548
1549                for ( const AlternativeFinder& arg : argAlternatives ) {
1550                        argExpansions.emplace_back();
1551                        auto& argE = argExpansions.back();
1552                        // argE.reserve( arg.alternatives.size() );
1553
1554                        for ( const Alternative& actual : arg ) {
1555                                argE.emplace_back( actual, indexer );
1556                        }
1557                }
1558
1559                AltList candidates;
1560                SemanticErrorException errors;
1561                for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
1562                        try {
1563                                PRINT(
1564                                        std::cerr << "working on alternative: " << std::endl;
1565                                        func->print( std::cerr, 8 );
1566                                )
1567                                // check if the type is pointer to function
1568                                if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
1569                                        if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
1570                                                Alternative newFunc( *func );
1571                                                referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1572                                                makeFunctionAlternatives( newFunc, function, argExpansions,
1573                                                        std::back_inserter( candidates ) );
1574                                        }
1575                                } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
1576                                        if ( ClassRef eqvClass = func->env.lookup( typeInst->name ) ) {
1577                                                if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.get_bound().type ) ) {
1578                                                        Alternative newFunc( *func );
1579                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1580                                                        makeFunctionAlternatives( newFunc, function, argExpansions,
1581                                                                std::back_inserter( candidates ) );
1582                                                } // if
1583                                        } // if
1584                                }
1585                        } catch ( SemanticErrorException &e ) {
1586                                errors.append( e );
1587                        }
1588                } // for
1589
1590                // try each function operator ?() with each function alternative
1591                if ( ! funcOpFinder.alternatives.empty() ) {
1592                        // add exploded function alternatives to front of argument list
1593                        std::vector<ExplodedActual> funcE;
1594                        funcE.reserve( funcFinder.alternatives.size() );
1595                        for ( const Alternative& actual : funcFinder ) {
1596                                funcE.emplace_back( actual, indexer );
1597                        }
1598                        argExpansions.insert( argExpansions.begin(), move(funcE) );
1599
1600                        for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
1601                                        funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
1602                                try {
1603                                        // check if type is a pointer to function
1604                                        if ( PointerType* pointer = dynamic_cast<PointerType*>(
1605                                                        funcOp->expr->get_result()->stripReferences() ) ) {
1606                                                if ( FunctionType* function =
1607                                                                dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
1608                                                        Alternative newFunc( *funcOp );
1609                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1610                                                        makeFunctionAlternatives( newFunc, function, argExpansions,
1611                                                                std::back_inserter( candidates ) );
1612                                                }
1613                                        }
1614                                } catch ( SemanticErrorException &e ) {
1615                                        errors.append( e );
1616                                }
1617                        }
1618                }
1619
1620                // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
1621                if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
1622
1623                // compute conversionsion costs
1624                for ( Alternative& withFunc : candidates ) {
1625                        Cost cvtCost = computeApplicationConversionCost( withFunc, indexer );
1626
1627                        PRINT(
1628                                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr );
1629                                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
1630                                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
1631                                std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
1632                                std::cerr << "formals are:" << std::endl;
1633                                printAll( function->get_parameters(), std::cerr, 8 );
1634                                std::cerr << "actuals are:" << std::endl;
1635                                printAll( appExpr->get_args(), std::cerr, 8 );
1636                                std::cerr << "bindings are:" << std::endl;
1637                                withFunc.env.print( std::cerr, 8 );
1638                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
1639                        )
1640                        if ( cvtCost != Cost::infinity ) {
1641                                withFunc.cvtCost = cvtCost;
1642                                alternatives.push_back( withFunc );
1643                        } // if
1644                } // for
1645
1646                candidates = move(alternatives);
1647
1648                // use a new list so that alternatives are not examined by addAnonConversions twice.
1649                AltList winners;
1650                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
1651
1652                // function may return struct or union value, in which case we need to add alternatives
1653                // for implicitconversions to each of the anonymous members, must happen after findMinCost
1654                // since anon conversions are never the cheapest expression
1655                for ( const Alternative & alt : winners ) {
1656                        addAnonConversions( alt );
1657                }
1658                spliceBegin( alternatives, winners );
1659
1660                if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
1661                        // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
1662                        // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
1663                        //   forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
1664                        //   const char * x = "hello world";
1665                        //   unsigned char ch = x[0];
1666                        // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
1667                        // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
1668                        // fix this issue in a more robust way.
1669                        targetType = nullptr;
1670                        postvisit( untypedExpr );
1671                }
1672        }
1673
1674        bool isLvalue( Expression *expr ) {
1675                // xxx - recurse into tuples?
1676                return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
1677        }
1678
1679        void AlternativeFinder::Finder::postvisit( AddressExpr *addressExpr ) {
1680                AlternativeFinder finder( indexer, env );
1681                finder.find( addressExpr->get_arg() );
1682                for ( Alternative& alt : finder.alternatives ) {
1683                        if ( isLvalue( alt.expr ) ) {
1684                                alternatives.push_back(
1685                                        Alternative{ new AddressExpr( alt.expr ), alt.env, alt.cost } );
1686                        } // if
1687                } // for
1688        }
1689
1690        void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
1691                alternatives.push_back( Alternative{ expr, env, Cost::zero } );
1692        }
1693
1694        Expression * restructureCast( Expression * argExpr, Type * toType, bool isGenerated ) {
1695                if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
1696                        // Argument expression is a tuple and the target type is not void and not a reference type.
1697                        // Cast each member of the tuple to its corresponding target type, producing the tuple of those
1698                        // cast expressions. If there are more components of the tuple than components in the target type,
1699                        // then excess components do not come out in the result expression (but UniqueExprs ensure that
1700                        // side effects will still be done).
1701                        if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
1702                                // expressions which may contain side effects require a single unique instance of the expression.
1703                                argExpr = new UniqueExpr( argExpr );
1704                        }
1705                        std::list< Expression * > componentExprs;
1706                        for ( unsigned int i = 0; i < toType->size(); i++ ) {
1707                                // cast each component
1708                                TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
1709                                componentExprs.push_back( restructureCast( idx, toType->getComponent( i ), isGenerated ) );
1710                        }
1711                        assert( componentExprs.size() > 0 );
1712                        // produce the tuple of casts
1713                        return new TupleExpr( componentExprs );
1714                } else {
1715                        // handle normally
1716                        CastExpr * ret = new CastExpr( argExpr, toType->clone() );
1717                        ret->isGenerated = isGenerated;
1718                        return ret;
1719                }
1720        }
1721
1722        void AlternativeFinder::Finder::postvisit( CastExpr *castExpr ) {
1723                Type *& toType = castExpr->get_result();
1724                assert( toType );
1725                toType = resolveTypeof( toType, indexer );
1726                SymTab::validateType( toType, &indexer );
1727                adjustExprType( toType, env, indexer );
1728
1729                AlternativeFinder finder( indexer, env );
1730                finder.targetType = toType;
1731                finder.findWithAdjustment( castExpr->arg );
1732
1733                AltList candidates;
1734                for ( Alternative & alt : finder.alternatives ) {
1735                        AssertionSet needAssertions, haveAssertions;
1736                        OpenVarSet openVars;
1737
1738                        alt.env.extractOpenVars( openVars );
1739
1740                        // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
1741                        // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
1742                        // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
1743                        // to.
1744                        int discardedValues = alt.expr->result->size() - castExpr->result->size();
1745                        if ( discardedValues < 0 ) continue;
1746                        // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1747                        // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1748                        // unification run for side-effects
1749                        unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
1750                                haveAssertions, openVars, indexer );
1751                        Cost thisCost = castCost( alt.expr->result, castExpr->result, indexer,
1752                                alt.env );
1753                        PRINT(
1754                                std::cerr << "working on cast with result: " << castExpr->result << std::endl;
1755                                std::cerr << "and expr type: " << alt.expr->result << std::endl;
1756                                std::cerr << "env: " << alt.env << std::endl;
1757                        )
1758                        if ( thisCost != Cost::infinity ) {
1759                                PRINT(
1760                                        std::cerr << "has finite cost." << std::endl;
1761                                )
1762                                // count one safe conversion for each value that is thrown away
1763                                thisCost.incSafe( discardedValues );
1764                                Alternative newAlt( restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ), alt.env,
1765                                        alt.cost, thisCost );
1766                                inferParameters( needAssertions, haveAssertions, std::move(newAlt), openVars,
1767                                        back_inserter( candidates ) );
1768                        } // if
1769                } // for
1770
1771                // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1772                // cvtCost member to the cost member (since the old cost is now irrelevant).  Thus, calling findMinCost twice
1773                // selects first based on argument cost, then on conversion cost.
1774                AltList minArgCost;
1775                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1776                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1777        }
1778
1779        void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
1780                assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
1781                AlternativeFinder finder( indexer, env );
1782                // don't prune here, since it's guaranteed all alternatives will have the same type
1783                finder.findWithoutPrune( castExpr->get_arg() );
1784                for ( Alternative & alt : finder.alternatives ) {
1785                        alternatives.push_back( Alternative(
1786                                new VirtualCastExpr( alt.expr, castExpr->get_result()->clone() ),
1787                                alt.env, alt.cost ) );
1788                }
1789        }
1790
1791        namespace {
1792                /// Gets name from untyped member expression (member must be NameExpr)
1793                const std::string& get_member_name( UntypedMemberExpr *memberExpr ) {
1794                        NameExpr * nameExpr = dynamic_cast< NameExpr * >( memberExpr->get_member() );
1795                        assert( nameExpr );
1796                        return nameExpr->get_name();
1797                }
1798        }
1799
1800        void AlternativeFinder::Finder::postvisit( UntypedMemberExpr *memberExpr ) {
1801                AlternativeFinder funcFinder( indexer, env );
1802                funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
1803                for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
1804                        // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
1805                        Cost cost = agg->cost;
1806                        Expression * aggrExpr = agg->expr->clone();
1807                        referenceToRvalueConversion( aggrExpr, cost );
1808
1809                        // find member of the given type
1810                        if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
1811                                addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1812                        } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
1813                                addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1814                        } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
1815                                addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() );
1816                        } // if
1817                } // for
1818        }
1819
1820        void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
1821                alternatives.push_back( Alternative( memberExpr, env, Cost::zero ) );
1822        }
1823
1824        void AlternativeFinder::Finder::postvisit( NameExpr *nameExpr ) {
1825                std::list< SymTab::Indexer::IdData > declList;
1826                indexer.lookupId( nameExpr->name, declList );
1827                PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
1828                for ( auto & data : declList ) {
1829                        Cost cost = Cost::zero;
1830                        Expression * newExpr = data.combine( cost );
1831
1832                        // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
1833                        // can't construct in place and use vector::back
1834                        Alternative newAlt( newExpr, env, Cost::zero, cost );
1835                        PRINT(
1836                                std::cerr << "decl is ";
1837                                data.id->print( std::cerr );
1838                                std::cerr << std::endl;
1839                                std::cerr << "newExpr is ";
1840                                newExpr->print( std::cerr );
1841                                std::cerr << std::endl;
1842                        )
1843                        renameTypes( newAlt.expr );
1844                        addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
1845                        alternatives.push_back( std::move(newAlt) );
1846                } // for
1847        }
1848
1849        void AlternativeFinder::Finder::postvisit( VariableExpr *variableExpr ) {
1850                // not sufficient to clone here, because variable's type may have changed
1851                // since the VariableExpr was originally created.
1852                alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
1853        }
1854
1855        void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
1856                alternatives.push_back( Alternative( constantExpr, env, Cost::zero ) );
1857        }
1858
1859        void AlternativeFinder::Finder::postvisit( SizeofExpr *sizeofExpr ) {
1860                if ( sizeofExpr->get_isType() ) {
1861                        Type * newType = sizeofExpr->get_type()->clone();
1862                        alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1863                } else {
1864                        // find all alternatives for the argument to sizeof
1865                        AlternativeFinder finder( indexer, env );
1866                        finder.find( sizeofExpr->get_expr() );
1867                        // find the lowest cost alternative among the alternatives, otherwise ambiguous
1868                        AltList winners;
1869                        findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1870                        if ( winners.size() != 1 ) {
1871                                SemanticError( sizeofExpr->get_expr(), "Ambiguous expression in sizeof operand: " );
1872                        } // if
1873                        // return the lowest cost alternative for the argument
1874                        Alternative &choice = winners.front();
1875                        referenceToRvalueConversion( choice.expr, choice.cost );
1876                        alternatives.push_back( Alternative( new SizeofExpr( choice.expr ), choice.env, Cost::zero ) );
1877                } // if
1878        }
1879
1880        void AlternativeFinder::Finder::postvisit( AlignofExpr *alignofExpr ) {
1881                if ( alignofExpr->get_isType() ) {
1882                        Type * newType = alignofExpr->get_type()->clone();
1883                        alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1884                } else {
1885                        // find all alternatives for the argument to sizeof
1886                        AlternativeFinder finder( indexer, env );
1887                        finder.find( alignofExpr->get_expr() );
1888                        // find the lowest cost alternative among the alternatives, otherwise ambiguous
1889                        AltList winners;
1890                        findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1891                        if ( winners.size() != 1 ) {
1892                                SemanticError( alignofExpr->get_expr(), "Ambiguous expression in alignof operand: " );
1893                        } // if
1894                        // return the lowest cost alternative for the argument
1895                        Alternative &choice = winners.front();
1896                        referenceToRvalueConversion( choice.expr, choice.cost );
1897                        alternatives.push_back( Alternative( new AlignofExpr( choice.expr ), choice.env, Cost::zero ) );
1898                } // if
1899        }
1900
1901        template< typename StructOrUnionType >
1902        void AlternativeFinder::Finder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
1903                std::list< Declaration* > members;
1904                aggInst->lookup( name, members );
1905                for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1906                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
1907                                alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
1908                                renameTypes( alternatives.back().expr );
1909                        } else {
1910                                assert( false );
1911                        }
1912                }
1913        }
1914
1915        void AlternativeFinder::Finder::postvisit( UntypedOffsetofExpr *offsetofExpr ) {
1916                AlternativeFinder funcFinder( indexer, env );
1917                // xxx - resolveTypeof?
1918                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
1919                        addOffsetof( structInst, offsetofExpr->member );
1920                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
1921                        addOffsetof( unionInst, offsetofExpr->member );
1922                }
1923        }
1924
1925        void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
1926                alternatives.push_back( Alternative( offsetofExpr, env, Cost::zero ) );
1927        }
1928
1929        void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
1930                alternatives.push_back( Alternative( offsetPackExpr, env, Cost::zero ) );
1931        }
1932
1933        namespace {
1934                void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
1935                        // assume no polymorphism
1936                        // assume no implicit conversions
1937                        assert( function->get_parameters().size() == 1 );
1938                        PRINT(
1939                                std::cerr << "resolvAttr: funcDecl is ";
1940                                data.id->print( std::cerr );
1941                                std::cerr << " argType is ";
1942                                argType->print( std::cerr );
1943                                std::cerr << std::endl;
1944                        )
1945                        const SymTab::Indexer & indexer = finder.get_indexer();
1946                        AltList & alternatives = finder.get_alternatives();
1947                        if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1948                                Cost cost = Cost::zero;
1949                                Expression * newExpr = data.combine( cost );
1950                                alternatives.push_back( Alternative( new AttrExpr( newExpr, argType->clone() ), env, Cost::zero, cost ) );
1951                                for ( DeclarationWithType * retVal : function->returnVals ) {
1952                                        alternatives.back().expr->result = retVal->get_type()->clone();
1953                                } // for
1954                        } // if
1955                }
1956        }
1957
1958        void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
1959                // assume no 'pointer-to-attribute'
1960                NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1961                assert( nameExpr );
1962                std::list< SymTab::Indexer::IdData > attrList;
1963                indexer.lookupId( nameExpr->get_name(), attrList );
1964                if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
1965                        for ( auto & data : attrList ) {
1966                                DeclarationWithType * id = data.id;
1967                                // check if the type is function
1968                                if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
1969                                        // assume exactly one parameter
1970                                        if ( function->get_parameters().size() == 1 ) {
1971                                                if ( attrExpr->get_isType() ) {
1972                                                        resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
1973                                                } else {
1974                                                        AlternativeFinder finder( indexer, env );
1975                                                        finder.find( attrExpr->get_expr() );
1976                                                        for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
1977                                                                if ( choice->expr->get_result()->size() == 1 ) {
1978                                                                        resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
1979                                                                } // fi
1980                                                        } // for
1981                                                } // if
1982                                        } // if
1983                                } // if
1984                        } // for
1985                } else {
1986                        for ( auto & data : attrList ) {
1987                                Cost cost = Cost::zero;
1988                                Expression * newExpr = data.combine( cost );
1989                                alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
1990                                renameTypes( alternatives.back().expr );
1991                        } // for
1992                } // if
1993        }
1994
1995        void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
1996                AlternativeFinder firstFinder( indexer, env );
1997                firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
1998                if ( firstFinder.alternatives.empty() ) return;
1999                AlternativeFinder secondFinder( indexer, env );
2000                secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
2001                if ( secondFinder.alternatives.empty() ) return;
2002                for ( const Alternative & first : firstFinder.alternatives ) {
2003                        for ( const Alternative & second : secondFinder.alternatives ) {
2004                                TypeEnvironment compositeEnv;
2005                                compositeEnv.simpleCombine( first.env );
2006                                compositeEnv.simpleCombine( second.env );
2007
2008                                LogicalExpr *newExpr = new LogicalExpr( first.expr, second.expr, logicalExpr->get_isAnd() );
2009                                alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
2010                        }
2011                }
2012        }
2013
2014        void AlternativeFinder::Finder::postvisit( ConditionalExpr *conditionalExpr ) {
2015                // find alternatives for condition
2016                AlternativeFinder firstFinder( indexer, env );
2017                firstFinder.findWithAdjustment( conditionalExpr->arg1 );
2018                if ( firstFinder.alternatives.empty() ) return;
2019                // find alternatives for true expression
2020                AlternativeFinder secondFinder( indexer, env );
2021                secondFinder.findWithAdjustment( conditionalExpr->arg2 );
2022                if ( secondFinder.alternatives.empty() ) return;
2023                // find alterantives for false expression
2024                AlternativeFinder thirdFinder( indexer, env );
2025                thirdFinder.findWithAdjustment( conditionalExpr->arg3 );
2026                if ( thirdFinder.alternatives.empty() ) return;
2027                for ( const Alternative & first : firstFinder.alternatives ) {
2028                        for ( const Alternative & second : secondFinder.alternatives ) {
2029                                for ( const Alternative & third : thirdFinder.alternatives ) {
2030                                        TypeEnvironment compositeEnv;
2031                                        compositeEnv.simpleCombine( first.env );
2032                                        compositeEnv.simpleCombine( second.env );
2033                                        compositeEnv.simpleCombine( third.env );
2034
2035                                        // unify true and false types, then infer parameters to produce new alternatives
2036                                        OpenVarSet openVars;
2037                                        AssertionSet needAssertions, haveAssertions;
2038                                        Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
2039                                        Type* commonType = nullptr;
2040                                        if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
2041                                                ConditionalExpr *newExpr = new ConditionalExpr( first.expr, second.expr, third.expr );
2042                                                newExpr->result = commonType ? commonType : second.expr->result->clone();
2043                                                // convert both options to the conditional result type
2044                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
2045                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
2046                                                newAlt.expr = newExpr;
2047                                                inferParameters( needAssertions, haveAssertions, std::move(newAlt), openVars, back_inserter( alternatives ) );
2048                                        } // if
2049                                } // for
2050                        } // for
2051                } // for
2052        }
2053
2054        void AlternativeFinder::Finder::postvisit( CommaExpr *commaExpr ) {
2055                TypeEnvironment newEnv( env );
2056                Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
2057                AlternativeFinder secondFinder( indexer, newEnv );
2058                secondFinder.findWithAdjustment( commaExpr->get_arg2() );
2059                for ( const Alternative & alt : secondFinder.alternatives ) {
2060                        alternatives.push_back( Alternative( new CommaExpr( newFirstArg, alt.expr ), alt.env, alt.cost ) );
2061                } // for
2062        }
2063
2064        void AlternativeFinder::Finder::postvisit( RangeExpr * rangeExpr ) {
2065                // resolve low and high, accept alternatives whose low and high types unify
2066                AlternativeFinder firstFinder( indexer, env );
2067                firstFinder.findWithAdjustment( rangeExpr->low );
2068                if ( firstFinder.alternatives.empty() ) return;
2069                AlternativeFinder secondFinder( indexer, env );
2070                secondFinder.findWithAdjustment( rangeExpr->high );
2071                if ( secondFinder.alternatives.empty() ) return;
2072                for ( const Alternative & first : firstFinder.alternatives ) {
2073                        for ( const Alternative & second : secondFinder.alternatives ) {
2074                                TypeEnvironment compositeEnv;
2075                                compositeEnv.simpleCombine( first.env );
2076                                compositeEnv.simpleCombine( second.env );
2077                                OpenVarSet openVars;
2078                                AssertionSet needAssertions, haveAssertions;
2079                                Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
2080                                Type* commonType = nullptr;
2081                                if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
2082                                        RangeExpr * newExpr = new RangeExpr( first.expr, second.expr );
2083                                        newExpr->result = commonType ? commonType : first.expr->result->clone();
2084                                        newAlt.expr = newExpr;
2085                                        inferParameters( needAssertions, haveAssertions, std::move(newAlt), openVars, back_inserter( alternatives ) );
2086                                } // if
2087                        } // for
2088                } // for
2089        }
2090
2091        void AlternativeFinder::Finder::postvisit( UntypedTupleExpr *tupleExpr ) {
2092                std::vector< AlternativeFinder > subExprAlternatives;
2093                altFinder.findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
2094                        back_inserter( subExprAlternatives ) );
2095                std::vector< AltList > possibilities;
2096                combos( subExprAlternatives.begin(), subExprAlternatives.end(),
2097                        back_inserter( possibilities ) );
2098                for ( const AltList& alts : possibilities ) {
2099                        std::list< Expression * > exprs;
2100                        makeExprList( alts, exprs );
2101
2102                        TypeEnvironment compositeEnv;
2103                        simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
2104                        alternatives.push_back(
2105                                Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
2106                } // for
2107        }
2108
2109        void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
2110                alternatives.push_back( Alternative( tupleExpr, env, Cost::zero ) );
2111        }
2112
2113        void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
2114                alternatives.push_back( Alternative( impCpCtorExpr, env, Cost::zero ) );
2115        }
2116
2117        void AlternativeFinder::Finder::postvisit( ConstructorExpr * ctorExpr ) {
2118                AlternativeFinder finder( indexer, env );
2119                // don't prune here, since it's guaranteed all alternatives will have the same type
2120                // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
2121                finder.findWithoutPrune( ctorExpr->get_callExpr() );
2122                for ( Alternative & alt : finder.alternatives ) {
2123                        alternatives.push_back( Alternative( new ConstructorExpr( alt.expr ), alt.env, alt.cost ) );
2124                }
2125        }
2126
2127        void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
2128                alternatives.push_back( Alternative( tupleExpr, env, Cost::zero ) );
2129        }
2130
2131        void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
2132                alternatives.push_back( Alternative( tupleAssignExpr, env, Cost::zero ) );
2133        }
2134
2135        void AlternativeFinder::Finder::postvisit( UniqueExpr *unqExpr ) {
2136                AlternativeFinder finder( indexer, env );
2137                finder.findWithAdjustment( unqExpr->get_expr() );
2138                for ( Alternative & alt : finder.alternatives ) {
2139                        // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
2140                        UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr, unqExpr->get_id() );
2141                        alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
2142                }
2143        }
2144
2145        void AlternativeFinder::Finder::postvisit( StmtExpr *stmtExpr ) {
2146                StmtExpr * newStmtExpr = stmtExpr->clone();
2147                ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
2148                // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
2149                alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
2150        }
2151
2152        void AlternativeFinder::Finder::postvisit( UntypedInitExpr *initExpr ) {
2153                // handle each option like a cast
2154                AltList candidates;
2155                PRINT(
2156                        std::cerr << "untyped init expr: " << initExpr << std::endl;
2157                )
2158                // O(N^2) checks of d-types with e-types
2159                for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
2160                        Type * toType = resolveTypeof( initAlt.type->clone(), indexer );
2161                        SymTab::validateType( toType, &indexer );
2162                        adjustExprType( toType, env, indexer );
2163                        // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
2164                        // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
2165                        // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
2166                        AlternativeFinder finder( indexer, env );
2167                        finder.targetType = toType;
2168                        finder.findWithAdjustment( initExpr->expr );
2169                        for ( Alternative & alt : finder.get_alternatives() ) {
2170                                TypeEnvironment newEnv( alt.env );
2171                                AssertionSet needAssertions, haveAssertions;
2172                                OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
2173                                PRINT(
2174                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
2175                                )
2176                                // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
2177                                // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
2178                                // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
2179                                // to.
2180                                int discardedValues = alt.expr->result->size() - toType->size();
2181                                if ( discardedValues < 0 ) continue;
2182                                // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
2183                                // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
2184                                // unification run for side-effects
2185                                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??
2186
2187                                Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
2188                                if ( thisCost != Cost::infinity ) {
2189                                        // count one safe conversion for each value that is thrown away
2190                                        thisCost.incSafe( discardedValues );
2191                                        Alternative newAlt( new InitExpr( restructureCast( alt.expr, toType, true ), initAlt.designation ), newEnv, alt.cost, thisCost );
2192                                        inferParameters( needAssertions, haveAssertions, std::move(newAlt), openVars, back_inserter( candidates ) );
2193                                }
2194                        }
2195                }
2196
2197                // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
2198                // cvtCost member to the cost member (since the old cost is now irrelevant).  Thus, calling findMinCost twice
2199                // selects first based on argument cost, then on conversion cost.
2200                AltList minArgCost;
2201                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
2202                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
2203        }
2204
2205        void AlternativeFinder::Finder::postvisit( InitExpr * ) {
2206                assertf( false, "AlternativeFinder should never see a resolved InitExpr." );
2207        }
2208
2209        void AlternativeFinder::Finder::postvisit( DeletedExpr * ) {
2210                assertf( false, "AlternativeFinder should never see a DeletedExpr." );
2211        }
2212
2213        void AlternativeFinder::Finder::postvisit( GenericExpr * ) {
2214                assertf( false, "_Generic is not yet supported." );
2215        }
2216} // namespace ResolvExpr
2217
2218// Local Variables: //
2219// tab-width: 4 //
2220// mode: c++ //
2221// compile-command: "make install" //
2222// End: //
Note: See TracBrowser for help on using the repository browser.