source: src/ResolvExpr/AlternativeFinder.cc @ 9160cb2

new-env
Last change on this file since 9160cb2 was 9160cb2, checked in by Aaron Moss <a3moss@…>, 3 years ago

Breadth-first assertion resolution builds, eats all the memory

  • Property mode set to 100644
File size: 87.7 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                                AssertionResnState& resn, AssertionPack&& match ) {
690                        addToIndexer( match.have, resn.indexer );
691                        resn.newNeed.insert( match.need.begin(), match.need.end() );
692                        resn.openVars = std::move(match.openVars);
693                        resn.alt.env = std::move(match.env);
694
695                        DeclarationWithType* candidate = match.cdata.id;
696                        assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
697                        for ( auto& a : match.need ) {
698                                if ( a.second.idChain.empty() ) {
699                                        a.second.idChain = assnInfo.idChain;
700                                        a.second.idChain.push_back( curDecl->get_uniqueId() );
701                                }
702                        }
703
704                        Expression* varExpr = match.cdata.combine( resn.alt.cvtCost );
705                        varExpr->result = match.adjType;
706
707                        // follow the current assertion's ID chain to find the correct set of inferred
708                        // parameters to add the candidate o (i.e. the set of inferred parameters belonging
709                        // to the entity which requested the assertion parameter)
710                        InferredParams* inferParams = &resn.alt.expr->inferParams;
711                        for ( UniqueId id : assnInfo.idChain ) {
712                                inferParams = (*inferParams)[ id ].inferParams.get();
713                        }
714
715                        (*inferParams)[ curDecl->get_uniqueId() ] = ParamEntry{
716                                candidate->get_uniqueId(), match.adjType, curDecl->get_type(), varExpr };
717                }
718
719                /// Resolves a single assertion, returning false if no satisfying assertion, binding it
720                /// if there is exactly one satisfying assertion, or adding to the defer-list if there
721                /// is more than one
722                bool resolveAssertion( DeclarationWithType* curDecl, AssertionSetValue& assnInfo, 
723                                AssertionResnState& resn ) {
724                        // skip unused assertions
725                        if ( ! assnInfo.isUsed ) return true;
726
727                        // lookup candidates for this assertion
728                        std::list< SymTab::Indexer::IdData > candidates;
729                        resn.indexer.lookupId( curDecl->name, candidates );
730
731                        // find the ones that unify with the desired type
732                        DeferList matches;
733                        for ( const auto& cdata : candidates ) {
734                                DeclarationWithType* candidate = cdata.id;
735
736                                // build independent unification context for candidate
737                                AssertionSet have, newNeed;
738                                TypeEnvironment newEnv{ resn.alt.env };
739                                OpenVarSet newOpenVars{ resn.openVars };
740                                Type* adjType = candidate->get_type()->clone();
741                                adjustExprType( adjType, newEnv, resn.indexer );
742                                renameTyVars( adjType );
743
744                                if ( unify( curDecl->get_type(), adjType, newEnv, 
745                                                newNeed, have, newOpenVars, resn.indexer ) ) {
746                                        matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have), 
747                                                std::move(newNeed), std::move(newOpenVars) );
748                                }
749                        }
750
751                        // Break if no suitable assertion
752                        if ( matches.empty() ) return false;
753
754                        // Defer if too many suitable assertions
755                        if ( matches.size() > 1 ) {
756                                resn.deferred.emplace_back( curDecl, assnInfo, std::move(matches) );
757                                return true;
758                        }
759
760                        // otherwise bind current match in ongoing scope
761                        bindAssertion( curDecl, assnInfo, resn, std::move(matches.front()) );
762                        return true;
763                }
764
765                /// Combo iterator that combines interpretations into an interpretation list, merging
766                /// their environments. Rejects an appended interpretation if the environments cannot
767                /// be merged.
768                class InterpretationEnvMerger {
769                        /// Current list of merged interpretations
770                        std::vector<DeferElement> crnt;
771                        /// Stack of environments, to support backtracking
772                        std::vector<TypeEnvironment> envs;
773                        /// Indexer to use for environment merges
774                        const SymTab::Indexer& indexer;
775                public:
776                        /// Outputs a pair consisting of the merged environment and the list of interpretations
777                        using OutType = std::pair<TypeEnvironment, std::vector<DeferElement>>;
778
779                        InterpretationEnvMerger( const TypeEnvironment& env, const SymTab::Indexer& indexer ) 
780                                : crnt{}, envs{}, indexer{indexer} { envs.push_back( env ); }
781
782                        ComboResult append( DeferElement i ) {
783                                TypeEnvironment env = envs.back();
784                                if ( ! env.combine( i.match.env, indexer ) ) return ComboResult::REJECT_THIS;
785                                crnt.push_back( i );
786                                envs.push_back( env );
787                                return ComboResult::ACCEPT;
788                        }
789
790                        void backtrack() {
791                                crnt.pop_back();
792                                envs.pop_back();
793                        }
794
795                        OutType finalize() { return { envs.back(), crnt }; }
796                };
797        }
798#endif
799
800        template< typename OutputIterator >
801        void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, Alternative &&newAlt, OpenVarSet &openVars, OutputIterator out ) {
802//      PRINT(
803//          std::cerr << "inferParameters: assertions needed are" << std::endl;
804//          printAll( need, std::cerr, 8 );
805//          )
806                SymTab::Indexer decls( indexer );
807                // PRINT(
808                //      std::cerr << "============= original indexer" << std::endl;
809                //      indexer.print( std::cerr );
810                //      std::cerr << "============= new indexer" << std::endl;
811                //      decls.print( std::cerr );
812                // )
813                addToIndexer( have, decls );
814#if 1
815                using ResnList = std::vector<AssertionResnState>;
816                ResnList resns{ AssertionResnState{ std::move(newAlt), need, openVars, decls } };
817                ResnList new_resns{};
818
819                // resolve assertions in breadth-first-order up to a limited number of levels deep
820                for ( int level = 0; level < recursionLimit; ++level ) {
821                        // scan over all mutually-compatible resolutions
822                        for ( auto& resn : resns ) {
823                                // make initial pass at matching assertions
824                                for ( auto& assn : resn.need ) {
825                                        if ( ! resolveAssertion( assn.first, assn.second, resn ) ) {
826                                                // fail early if any assertion fails to resolve
827                                                goto nextResn;
828                                        }
829                                }
830
831                                if ( ! resn.deferred.empty() ) {
832                                        // resolve deferred assertions by mutual compatibility
833
834                                        std::vector<InterpretationEnvMerger::OutType> compatible = filterCombos( 
835                                                resn.deferred, InterpretationEnvMerger{ resn.alt.env, resn.indexer });
836                                       
837                                        for ( auto& compat : compatible ) {
838                                                AssertionResnState new_resn = resn;
839
840                                                // add compatible assertions to new resolution state
841                                                for ( DeferElement el : compat.second ) {
842                                                        bindAssertion( 
843                                                                el.curDecl, el.assnInfo, new_resn, AssertionPack{el.match} );
844                                                }
845
846                                                // set mutual environment into resolution state
847                                                new_resn.alt.env = std::move(compat.first);
848
849                                                // add successful match or push back next state
850                                                if ( new_resn.newNeed.empty() ) {
851                                                        *out++ = new_resn.alt;
852                                                } else {
853                                                        new_resns.emplace_back( std::move(new_resn), IterateState );
854                                                }
855                                        }
856                                } else {
857                                        // add successful match or push back next state
858                                        if ( resn.newNeed.empty() ) {
859                                                *out++ = resn.alt;
860                                        } else {
861                                                new_resns.emplace_back( std::move(resn), IterateState );
862                                        }
863                                }
864                        nextResn:; }
865                       
866                        // finish or reset for next round
867                        if ( new_resns.empty() ) return;
868                        resns.swap( new_resns );
869                        new_resns.clear();
870                }
871                // if reaches here, exceeded recursion limit
872                SemanticError( newAlt.expr->location, "Too many recursive assertions" );
873
874#else           
875                AssertionSet newNeed;
876                PRINT(
877                        std::cerr << "env is: " << std::endl;
878                        newAlt.env.print( std::cerr, 0 );
879                        std::cerr << std::endl;
880                )
881
882                inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out );
883//      PRINT(
884//          std::cerr << "declaration 14 is ";
885//          Declaration::declFromId
886//          *out++ = newAlt;
887//          )
888#endif
889        }
890
891        /// Gets a default value from an initializer, nullptr if not present
892        ConstantExpr* getDefaultValue( Initializer* init ) {
893                if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
894                        if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->value ) ) {
895                                return dynamic_cast<ConstantExpr*>( ce->arg );
896                        } else {
897                                return dynamic_cast<ConstantExpr*>( si->value );
898                        }
899                }
900                return nullptr;
901        }
902
903        /// State to iteratively build a match of parameter expressions to arguments
904        struct ArgPack {
905                std::size_t parent;                ///< Index of parent pack
906                Expression* expr;                  ///< The argument stored here
907                Cost cost;                         ///< The cost of this argument
908                TypeEnvironment env;               ///< Environment for this pack
909                AssertionSet need;                 ///< Assertions outstanding for this pack
910                AssertionSet have;                 ///< Assertions found for this pack
911                OpenVarSet openVars;               ///< Open variables for this pack
912                unsigned nextArg;                  ///< Index of next argument in arguments list
913                unsigned tupleStart;               ///< Number of tuples that start at this index
914                unsigned nextExpl;                 ///< Index of next exploded element
915                unsigned explAlt;                  ///< Index of alternative for nextExpl > 0
916
917                ArgPack()
918                        : parent(0), expr(nullptr), cost(Cost::zero), env(), need(), have(), openVars(), 
919                          nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
920
921                ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
922                                const OpenVarSet& openVars, Cost initCost = Cost::zero)
923                        : parent(0), expr(nullptr), cost(initCost), env(env), need(need), have(have),
924                          openVars(openVars), nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
925
926                ArgPack(std::size_t parent, Expression* expr, TypeEnvironment&& env, AssertionSet&& need,
927                                AssertionSet&& have, OpenVarSet&& openVars, unsigned nextArg,
928                                unsigned tupleStart = 0, Cost cost = Cost::zero, unsigned nextExpl = 0,
929                                unsigned explAlt = 0 )
930                        : parent(parent), expr(expr), cost(cost), env(move(env)), need(move(need)),
931                          have(move(have)), openVars(move(openVars)), nextArg(nextArg), tupleStart(tupleStart),
932                          nextExpl(nextExpl), explAlt(explAlt) {}
933
934                ArgPack(const ArgPack& o, TypeEnvironment&& env, AssertionSet&& need, AssertionSet&& have,
935                                OpenVarSet&& openVars, unsigned nextArg, Cost added )
936                        : parent(o.parent), expr(o.expr), cost(o.cost + added), env(move(env)), 
937                          need(move(need)), have(move(have)), openVars(move(openVars)), nextArg(nextArg), 
938                          tupleStart(o.tupleStart), nextExpl(0), explAlt(0) {}
939
940                /// true iff this pack is in the middle of an exploded argument
941                bool hasExpl() const { return nextExpl > 0; }
942
943                /// Gets the list of exploded alternatives for this pack
944                const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
945                        return args[nextArg-1][explAlt];
946                }
947
948                /// Ends a tuple expression, consolidating the appropriate actuals
949                void endTuple( const std::vector<ArgPack>& packs ) {
950                        // add all expressions in tuple to list, summing cost
951                        std::list<Expression*> exprs;
952                        const ArgPack* pack = this;
953                        if ( expr ) { exprs.push_front( expr ); }
954                        while ( pack->tupleStart == 0 ) {
955                                pack = &packs[pack->parent];
956                                exprs.push_front( pack->expr );
957                                cost += pack->cost;
958                        }
959                        // reset pack to appropriate tuple
960                        expr = new TupleExpr{ exprs };
961                        tupleStart = pack->tupleStart - 1;
962                        parent = pack->parent;
963                }
964        };
965
966        /// Instantiates an argument to match a formal, returns false if no results left
967        bool instantiateArgument( Type* formalType, Initializer* initializer,
968                        const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
969                        const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
970                if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
971                        // formalType is a TupleType - group actuals into a TupleExpr
972                        ++nTuples;
973                        for ( Type* type : *tupleType ) {
974                                // xxx - dropping initializer changes behaviour from previous, but seems correct
975                                // ^^^ need to handle the case where a tuple has a default argument
976                                if ( ! instantiateArgument(
977                                                type, nullptr, args, results, genStart, indexer, nTuples ) )
978                                        return false;
979                                nTuples = 0;
980                        }
981                        // re-consititute tuples for final generation
982                        for ( auto i = genStart; i < results.size(); ++i ) {
983                                results[i].endTuple( results );
984                        }
985                        return true;
986                } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
987                        // formalType is a ttype, consumes all remaining arguments
988                        // xxx - mixing default arguments with variadic??
989
990                        // completed tuples; will be spliced to end of results to finish
991                        std::vector<ArgPack> finalResults{};
992
993                        // iterate until all results completed
994                        std::size_t genEnd;
995                        ++nTuples;
996                        do {
997                                genEnd = results.size();
998
999                                // add another argument to results
1000                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
1001                                        auto nextArg = results[i].nextArg;
1002
1003                                        // use next element of exploded tuple if present
1004                                        if ( results[i].hasExpl() ) {
1005                                                const ExplodedActual& expl = results[i].getExpl( args );
1006
1007                                                unsigned nextExpl = results[i].nextExpl + 1;
1008                                                if ( nextExpl == expl.exprs.size() ) {
1009                                                        nextExpl = 0;
1010                                                }
1011
1012                                                results.emplace_back(
1013                                                        i, expl.exprs[results[i].nextExpl], copy(results[i].env),
1014                                                        copy(results[i].need), copy(results[i].have),
1015                                                        copy(results[i].openVars), nextArg, nTuples, Cost::zero, nextExpl,
1016                                                        results[i].explAlt );
1017
1018                                                continue;
1019                                        }
1020
1021                                        // finish result when out of arguments
1022                                        if ( nextArg >= args.size() ) {
1023                                                ArgPack newResult{
1024                                                        results[i].env, results[i].need, results[i].have,
1025                                                        results[i].openVars };
1026                                                newResult.nextArg = nextArg;
1027                                                Type* argType;
1028
1029                                                if ( nTuples > 0 || ! results[i].expr ) {
1030                                                        // first iteration or no expression to clone,
1031                                                        // push empty tuple expression
1032                                                        newResult.parent = i;
1033                                                        std::list<Expression*> emptyList;
1034                                                        newResult.expr = new TupleExpr{ emptyList };
1035                                                        argType = newResult.expr->get_result();
1036                                                } else {
1037                                                        // clone result to collect tuple
1038                                                        newResult.parent = results[i].parent;
1039                                                        newResult.cost = results[i].cost;
1040                                                        newResult.tupleStart = results[i].tupleStart;
1041                                                        newResult.expr = results[i].expr;
1042                                                        argType = newResult.expr->get_result();
1043
1044                                                        if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
1045                                                                // the case where a ttype value is passed directly is special,
1046                                                                // e.g. for argument forwarding purposes
1047                                                                // xxx - what if passing multiple arguments, last of which is
1048                                                                //       ttype?
1049                                                                // xxx - what would happen if unify was changed so that unifying
1050                                                                //       tuple
1051                                                                // types flattened both before unifying lists? then pass in
1052                                                                // TupleType (ttype) below.
1053                                                                --newResult.tupleStart;
1054                                                        } else {
1055                                                                // collapse leftover arguments into tuple
1056                                                                newResult.endTuple( results );
1057                                                                argType = newResult.expr->get_result();
1058                                                        }
1059                                                }
1060
1061                                                // check unification for ttype before adding to final
1062                                                if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have,
1063                                                                newResult.openVars, indexer ) ) {
1064                                                        finalResults.push_back( move(newResult) );
1065                                                }
1066
1067                                                continue;
1068                                        }
1069
1070                                        // add each possible next argument
1071                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1072                                                const ExplodedActual& expl = args[nextArg][j];
1073
1074                                                // fresh copies of parent parameters for this iteration
1075                                                TypeEnvironment env = results[i].env;
1076                                                OpenVarSet openVars = results[i].openVars;
1077
1078                                                env.addActual( expl.env, openVars );
1079
1080                                                // skip empty tuple arguments by (near-)cloning parent into next gen
1081                                                if ( expl.exprs.empty() ) {
1082                                                        results.emplace_back(
1083                                                                results[i], move(env), copy(results[i].need),
1084                                                                copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
1085
1086                                                        continue;
1087                                                }
1088
1089                                                // add new result
1090                                                results.emplace_back(
1091                                                        i, expl.exprs.front(), move(env), copy(results[i].need),
1092                                                        copy(results[i].have), move(openVars), nextArg + 1,
1093                                                        nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1094                                        }
1095                                }
1096
1097                                // reset for next round
1098                                genStart = genEnd;
1099                                nTuples = 0;
1100                        } while ( genEnd != results.size() );
1101
1102                        // splice final results onto results
1103                        for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
1104                                results.push_back( move(finalResults[i]) );
1105                        }
1106                        return ! finalResults.empty();
1107                }
1108
1109                // iterate each current subresult
1110                std::size_t genEnd = results.size();
1111                for ( std::size_t i = genStart; i < genEnd; ++i ) {
1112                        auto nextArg = results[i].nextArg;
1113
1114                        // use remainder of exploded tuple if present
1115                        if ( results[i].hasExpl() ) {
1116                                const ExplodedActual& expl = results[i].getExpl( args );
1117                                Expression* expr = expl.exprs[results[i].nextExpl];
1118
1119                                TypeEnvironment env = results[i].env;
1120                                AssertionSet need = results[i].need, have = results[i].have;
1121                                OpenVarSet openVars = results[i].openVars;
1122
1123                                Type* actualType = expr->get_result();
1124
1125                                PRINT(
1126                                        std::cerr << "formal type is ";
1127                                        formalType->print( std::cerr );
1128                                        std::cerr << std::endl << "actual type is ";
1129                                        actualType->print( std::cerr );
1130                                        std::cerr << std::endl;
1131                                )
1132
1133                                if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
1134                                        unsigned nextExpl = results[i].nextExpl + 1;
1135                                        if ( nextExpl == expl.exprs.size() ) {
1136                                                nextExpl = 0;
1137                                        }
1138
1139                                        results.emplace_back(
1140                                                i, expr, move(env), move(need), move(have), move(openVars), nextArg,
1141                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
1142                                }
1143
1144                                continue;
1145                        }
1146
1147                        // use default initializers if out of arguments
1148                        if ( nextArg >= args.size() ) {
1149                                if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
1150                                        if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
1151                                                TypeEnvironment env = results[i].env;
1152                                                AssertionSet need = results[i].need, have = results[i].have;
1153                                                OpenVarSet openVars = results[i].openVars;
1154
1155                                                if ( unify( formalType, cnst->get_type(), env, need, have, openVars,
1156                                                                indexer ) ) {
1157                                                        results.emplace_back(
1158                                                                i, new DefaultArgExpr( cnstExpr ), move(env), move(need), move(have),
1159                                                                move(openVars), nextArg, nTuples );
1160                                                }
1161                                        }
1162                                }
1163
1164                                continue;
1165                        }
1166
1167                        // Check each possible next argument
1168                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1169                                const ExplodedActual& expl = args[nextArg][j];
1170
1171                                // fresh copies of parent parameters for this iteration
1172                                TypeEnvironment env = results[i].env;
1173                                AssertionSet need = results[i].need, have = results[i].have;
1174                                OpenVarSet openVars = results[i].openVars;
1175
1176                                env.addActual( expl.env, openVars );
1177
1178                                // skip empty tuple arguments by (near-)cloning parent into next gen
1179                                if ( expl.exprs.empty() ) {
1180                                        results.emplace_back(
1181                                                results[i], move(env), move(need), move(have), move(openVars),
1182                                                nextArg + 1, expl.cost );
1183
1184                                        continue;
1185                                }
1186
1187                                // consider only first exploded actual
1188                                Expression* expr = expl.exprs.front();
1189                                Type* actualType = expr->result->clone();
1190
1191                                PRINT(
1192                                        std::cerr << "formal type is ";
1193                                        formalType->print( std::cerr );
1194                                        std::cerr << std::endl << "actual type is ";
1195                                        actualType->print( std::cerr );
1196                                        std::cerr << std::endl;
1197                                )
1198
1199                                // attempt to unify types
1200                                if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
1201                                        // add new result
1202                                        results.emplace_back(
1203                                                i, expr, move(env), move(need), move(have), move(openVars), nextArg + 1,
1204                                                nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1205                                }
1206                        }
1207                }
1208
1209                // reset for next parameter
1210                genStart = genEnd;
1211
1212                return genEnd != results.size();
1213        }
1214
1215#if !1
1216        namespace {
1217
1218                struct CountSpecs : public WithVisitorRef<CountSpecs>, WithShortCircuiting {
1219
1220                        void postvisit(PointerType*) {
1221                                // mark specialization of base type
1222                                if ( count >= 0 ) ++count;
1223                        }
1224
1225                        void postvisit(ArrayType*) {
1226                                // mark specialization of base type
1227                                if ( count >= 0 ) ++count;
1228                        }
1229
1230                        void postvisit(ReferenceType*) {
1231                                // mark specialization of base type -- xxx maybe not?
1232                                if ( count >= 0 ) ++count;
1233                        }
1234
1235                private:
1236                        // takes minimum non-negative count over parameter/return list
1237                        void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {
1238                                for ( DeclarationWithType* dwt : dwts ) {
1239                                        count = -1;
1240                                        maybeAccept( dwt->get_type(), *visitor );
1241                                        if ( count != -1 && count < mincount ) mincount = count;
1242                                }
1243                        }
1244
1245                public:
1246                        void previsit(FunctionType*) {
1247                                // override default child visiting behaviour
1248                                visit_children = false;
1249                        }
1250
1251                        void postvisit(FunctionType* fty) {
1252                                // take minimal set value of count over ->returnVals and ->parameters
1253                                int mincount = std::numeric_limits<int>::max();
1254                                takeminover( mincount, fty->parameters );
1255                                takeminover( mincount, fty->returnVals );
1256                                // add another level to mincount if set
1257                                count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
1258                        }
1259
1260                private:
1261                        // returns minimum non-negative count + 1 over type parameters (-1 if none such)
1262                        int minover( std::list<Expression*>& parms ) {
1263                                int mincount = std::numeric_limits<int>::max();
1264                                for ( Expression* parm : parms ) {
1265                                        count = -1;
1266                                        maybeAccept( parm->get_result(), *visitor );
1267                                        if ( count != -1 && count < mincount ) mincount = count;
1268                                }
1269                                return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
1270                        }
1271                       
1272                public:
1273                        void previsit(StructInstType*) {
1274                                // override default child behaviour
1275                                visit_children = false;
1276                        }
1277
1278                        void postvisit(StructInstType* sity) {
1279                                // look for polymorphic parameters
1280                                count = minover( sity->parameters );
1281                        }
1282
1283                        void previsit(UnionInstType*) {
1284                                // override default child behaviour
1285                                visit_children = false;
1286                        }
1287
1288                        void postvisit(UnionInstType* uity) {
1289                                // look for polymorphic parameters
1290                                count = minover( uity->parameters );
1291                        }
1292
1293                        void postvisit(TypeInstType*) {
1294                                // note polymorphic type (which may be specialized)
1295                                // xxx - maybe account for open/closed type variables
1296                                count = 0;
1297                        }
1298
1299                        void previsit(TupleType*) {
1300                                // override default child behaviour
1301                                visit_children = false;
1302                        }
1303
1304                        void postvisit(TupleType* tty) {
1305                                // take minimum non-negative count
1306                                int mincount = std::numeric_limits<int>::max();
1307                                for ( Type* ty : tty->types ) {
1308                                        count = -1;
1309                                        maybeAccept( ty, *visitor );
1310                                        if ( count != -1 && count < mincount ) mincount = count;
1311                                }
1312                                // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
1313                                count = mincount < std::numeric_limits<int>::max() ? mincount + 1: -1;
1314                        }
1315
1316                        int get_count() const { return count >= 0 ? count : 0; }
1317                private:
1318                        int count = -1;
1319                };
1320
1321                /// Counts the specializations in the types in a function parameter or return list
1322                int countSpecs( std::list<DeclarationWithType*>& dwts ) {
1323                        int k = 0;
1324                        for ( DeclarationWithType* dwt : dwts ) {
1325                                PassVisitor<CountSpecs> counter;
1326                                maybeAccept( dwt->get_type(), *counter.pass.visitor );
1327                                k += counter.pass.get_count();
1328                        }
1329                        return k;
1330                }
1331
1332                /// Calculates the inherent costs in a function declaration; varCost for the number of
1333                /// type variables and specCost for type assertions, as well as PolyType specializations
1334                /// in the parameter and return lists.
1335                Cost declCost( FunctionType* funcType ) {
1336                        Cost k = Cost::zero;
1337
1338                        // add cost of type variables
1339                        k.incVar( funcType->forall.size() );
1340
1341                        // subtract cost of type assertions
1342                        for ( TypeDecl* td : funcType->forall ) {
1343                                k.decSpec( td->assertions.size() );
1344                        }
1345
1346                        // count specialized polymorphic types in parameter/return lists
1347                        k.decSpec( countSpecs( funcType->parameters ) );
1348                        k.decSpec( countSpecs( funcType->returnVals ) );
1349
1350                        return k;
1351                }
1352        }
1353#endif
1354
1355        template<typename OutputIterator>
1356        void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func, 
1357                        ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out ) {
1358                ApplicationExpr *appExpr = new ApplicationExpr( func.expr );
1359                // sum cost and accumulate actuals
1360                std::list<Expression*>& args = appExpr->args;
1361                Cost cost = func.cost;
1362                const ArgPack* pack = &result;
1363                while ( pack->expr ) {
1364                        args.push_front( pack->expr );
1365                        cost += pack->cost;
1366                        pack = &results[pack->parent];
1367                }
1368                // build and validate new alternative
1369                Alternative newAlt( appExpr, result.env, cost );
1370                PRINT(
1371                        std::cerr << "instantiate function success: " << appExpr << std::endl;
1372                        std::cerr << "need assertions:" << std::endl;
1373                        printAssertionSet( result.need, std::cerr, 8 );
1374                )
1375                inferParameters( result.need, result.have, std::move(newAlt), result.openVars, out );
1376        }
1377
1378        template<typename OutputIterator>
1379        void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
1380                        FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
1381                OpenVarSet funcOpenVars;
1382                AssertionSet funcNeed, funcHave;
1383                TypeEnvironment funcEnv( func.env );
1384                makeUnifiableVars( funcType, funcOpenVars, funcNeed );
1385                // add all type variables as open variables now so that those not used in the parameter
1386                // list are still considered open.
1387                funcEnv.add( funcType->forall );
1388
1389                if ( targetType && ! targetType->isVoid() && ! funcType->returnVals.empty() ) {
1390                        // attempt to narrow based on expected target type
1391                        Type * returnType = funcType->returnVals.front()->get_type();
1392                        if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
1393                                        indexer ) ) {
1394                                // unification failed, don't pursue this function alternative
1395                                return;
1396                        }
1397                }
1398
1399                // calculate declaration cost of function (+vars-spec)
1400#if !1
1401                Cost funcCost = declCost( funcType );
1402#else
1403                Cost funcCost = Cost::zero;
1404#endif
1405
1406                // iteratively build matches, one parameter at a time
1407                std::vector<ArgPack> results;
1408                results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars, funcCost } );
1409                std::size_t genStart = 0;
1410
1411                for ( DeclarationWithType* formal : funcType->parameters ) {
1412                        ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
1413                        if ( ! instantiateArgument(
1414                                        obj->type, obj->init, args, results, genStart, indexer ) )
1415                                return;
1416                }
1417
1418                if ( funcType->get_isVarArgs() ) {
1419                        // append any unused arguments to vararg pack
1420                        std::size_t genEnd;
1421                        do {
1422                                genEnd = results.size();
1423
1424                                // iterate results
1425                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
1426                                        auto nextArg = results[i].nextArg;
1427
1428                                        // use remainder of exploded tuple if present
1429                                        if ( results[i].hasExpl() ) {
1430                                                const ExplodedActual& expl = results[i].getExpl( args );
1431
1432                                                unsigned nextExpl = results[i].nextExpl + 1;
1433                                                if ( nextExpl == expl.exprs.size() ) {
1434                                                        nextExpl = 0;
1435                                                }
1436
1437                                                results.emplace_back(
1438                                                        i, expl.exprs[results[i].nextExpl], copy(results[i].env),
1439                                                        copy(results[i].need), copy(results[i].have),
1440                                                        copy(results[i].openVars), nextArg, 0, Cost::zero, nextExpl,
1441                                                        results[i].explAlt );
1442
1443                                                continue;
1444                                        }
1445
1446                                        // finish result when out of arguments
1447                                        if ( nextArg >= args.size() ) {
1448                                                validateFunctionAlternative( func, results[i], results, out );
1449
1450                                                continue;
1451                                        }
1452
1453                                        // add each possible next argument
1454                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1455                                                const ExplodedActual& expl = args[nextArg][j];
1456
1457                                                // fresh copies of parent parameters for this iteration
1458                                                TypeEnvironment env = results[i].env;
1459                                                OpenVarSet openVars = results[i].openVars;
1460
1461                                                env.addActual( expl.env, openVars );
1462
1463                                                // skip empty tuple arguments by (near-)cloning parent into next gen
1464                                                if ( expl.exprs.empty() ) {
1465                                                        results.emplace_back(
1466                                                                results[i], move(env), copy(results[i].need),
1467                                                                copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
1468
1469                                                        continue;
1470                                                }
1471
1472                                                // add new result
1473                                                results.emplace_back(
1474                                                        i, expl.exprs.front(), move(env), copy(results[i].need),
1475                                                        copy(results[i].have), move(openVars), nextArg + 1, 0,
1476                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1477                                        }
1478                                }
1479
1480                                genStart = genEnd;
1481                        } while ( genEnd != results.size() );
1482                } else {
1483                        // filter out results that don't use all the arguments
1484                        for ( std::size_t i = genStart; i < results.size(); ++i ) {
1485                                ArgPack& result = results[i];
1486                                if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
1487                                        validateFunctionAlternative( func, result, results, out );
1488                                }
1489                        }
1490                }
1491        }
1492
1493        void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
1494                AlternativeFinder funcFinder( indexer, env );
1495                funcFinder.findWithAdjustment( untypedExpr->function );
1496                // if there are no function alternatives, then proceeding is a waste of time.
1497                // xxx - findWithAdjustment throws, so this check and others like it shouldn't be necessary.
1498                if ( funcFinder.alternatives.empty() ) return;
1499
1500                std::vector< AlternativeFinder > argAlternatives;
1501                altFinder.findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
1502                        back_inserter( argAlternatives ) );
1503
1504                // take care of possible tuple assignments
1505                // if not tuple assignment, assignment is taken care of as a normal function call
1506                Tuples::handleTupleAssignment( altFinder, untypedExpr, argAlternatives );
1507
1508                // find function operators
1509                static auto *opExpr = new_static_root<NameExpr>( "?()" );
1510                AlternativeFinder funcOpFinder( indexer, env );
1511                // it's ok if there aren't any defined function ops
1512                funcOpFinder.maybeFind( opExpr );
1513                PRINT(
1514                        std::cerr << "known function ops:" << std::endl;
1515                        printAlts( funcOpFinder.alternatives, std::cerr, 1 );
1516                )
1517
1518                // pre-explode arguments
1519                ExplodedArgs argExpansions;
1520                argExpansions.reserve( argAlternatives.size() );
1521
1522                for ( const AlternativeFinder& arg : argAlternatives ) {
1523                        argExpansions.emplace_back();
1524                        auto& argE = argExpansions.back();
1525                        // argE.reserve( arg.alternatives.size() );
1526
1527                        for ( const Alternative& actual : arg ) {
1528                                argE.emplace_back( actual, indexer );
1529                        }
1530                }
1531
1532                AltList candidates;
1533                SemanticErrorException errors;
1534                for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
1535                        try {
1536                                PRINT(
1537                                        std::cerr << "working on alternative: " << std::endl;
1538                                        func->print( std::cerr, 8 );
1539                                )
1540                                // check if the type is pointer to function
1541                                if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
1542                                        if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
1543                                                Alternative newFunc( *func );
1544                                                referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1545                                                makeFunctionAlternatives( newFunc, function, argExpansions,
1546                                                        std::back_inserter( candidates ) );
1547                                        }
1548                                } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
1549                                        if ( ClassRef eqvClass = func->env.lookup( typeInst->name ) ) {
1550                                                if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.get_bound().type ) ) {
1551                                                        Alternative newFunc( *func );
1552                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1553                                                        makeFunctionAlternatives( newFunc, function, argExpansions,
1554                                                                std::back_inserter( candidates ) );
1555                                                } // if
1556                                        } // if
1557                                }
1558                        } catch ( SemanticErrorException &e ) {
1559                                errors.append( e );
1560                        }
1561                } // for
1562
1563                // try each function operator ?() with each function alternative
1564                if ( ! funcOpFinder.alternatives.empty() ) {
1565                        // add exploded function alternatives to front of argument list
1566                        std::vector<ExplodedActual> funcE;
1567                        funcE.reserve( funcFinder.alternatives.size() );
1568                        for ( const Alternative& actual : funcFinder ) {
1569                                funcE.emplace_back( actual, indexer );
1570                        }
1571                        argExpansions.insert( argExpansions.begin(), move(funcE) );
1572
1573                        for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
1574                                        funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
1575                                try {
1576                                        // check if type is a pointer to function
1577                                        if ( PointerType* pointer = dynamic_cast<PointerType*>(
1578                                                        funcOp->expr->get_result()->stripReferences() ) ) {
1579                                                if ( FunctionType* function =
1580                                                                dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
1581                                                        Alternative newFunc( *funcOp );
1582                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1583                                                        makeFunctionAlternatives( newFunc, function, argExpansions,
1584                                                                std::back_inserter( candidates ) );
1585                                                }
1586                                        }
1587                                } catch ( SemanticErrorException &e ) {
1588                                        errors.append( e );
1589                                }
1590                        }
1591                }
1592
1593                // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
1594                if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
1595
1596                // compute conversionsion costs
1597                for ( Alternative& withFunc : candidates ) {
1598                        Cost cvtCost = computeApplicationConversionCost( withFunc, indexer );
1599
1600                        PRINT(
1601                                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr );
1602                                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
1603                                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
1604                                std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
1605                                std::cerr << "formals are:" << std::endl;
1606                                printAll( function->get_parameters(), std::cerr, 8 );
1607                                std::cerr << "actuals are:" << std::endl;
1608                                printAll( appExpr->get_args(), std::cerr, 8 );
1609                                std::cerr << "bindings are:" << std::endl;
1610                                withFunc.env.print( std::cerr, 8 );
1611                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
1612                        )
1613                        if ( cvtCost != Cost::infinity ) {
1614                                withFunc.cvtCost = cvtCost;
1615                                alternatives.push_back( withFunc );
1616                        } // if
1617                } // for
1618
1619                candidates = move(alternatives);
1620
1621                // use a new list so that alternatives are not examined by addAnonConversions twice.
1622                AltList winners;
1623                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
1624
1625                // function may return struct or union value, in which case we need to add alternatives
1626                // for implicitconversions to each of the anonymous members, must happen after findMinCost
1627                // since anon conversions are never the cheapest expression
1628                for ( const Alternative & alt : winners ) {
1629                        addAnonConversions( alt );
1630                }
1631                spliceBegin( alternatives, winners );
1632
1633                if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
1634                        // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
1635                        // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
1636                        //   forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
1637                        //   const char * x = "hello world";
1638                        //   unsigned char ch = x[0];
1639                        // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
1640                        // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
1641                        // fix this issue in a more robust way.
1642                        targetType = nullptr;
1643                        postvisit( untypedExpr );
1644                }
1645        }
1646
1647        bool isLvalue( Expression *expr ) {
1648                // xxx - recurse into tuples?
1649                return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
1650        }
1651
1652        void AlternativeFinder::Finder::postvisit( AddressExpr *addressExpr ) {
1653                AlternativeFinder finder( indexer, env );
1654                finder.find( addressExpr->get_arg() );
1655                for ( Alternative& alt : finder.alternatives ) {
1656                        if ( isLvalue( alt.expr ) ) {
1657                                alternatives.push_back(
1658                                        Alternative{ new AddressExpr( alt.expr ), alt.env, alt.cost } );
1659                        } // if
1660                } // for
1661        }
1662
1663        void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
1664                alternatives.push_back( Alternative{ expr, env, Cost::zero } );
1665        }
1666
1667        Expression * restructureCast( Expression * argExpr, Type * toType, bool isGenerated ) {
1668                if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
1669                        // Argument expression is a tuple and the target type is not void and not a reference type.
1670                        // Cast each member of the tuple to its corresponding target type, producing the tuple of those
1671                        // cast expressions. If there are more components of the tuple than components in the target type,
1672                        // then excess components do not come out in the result expression (but UniqueExprs ensure that
1673                        // side effects will still be done).
1674                        if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
1675                                // expressions which may contain side effects require a single unique instance of the expression.
1676                                argExpr = new UniqueExpr( argExpr );
1677                        }
1678                        std::list< Expression * > componentExprs;
1679                        for ( unsigned int i = 0; i < toType->size(); i++ ) {
1680                                // cast each component
1681                                TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
1682                                componentExprs.push_back( restructureCast( idx, toType->getComponent( i ), isGenerated ) );
1683                        }
1684                        assert( componentExprs.size() > 0 );
1685                        // produce the tuple of casts
1686                        return new TupleExpr( componentExprs );
1687                } else {
1688                        // handle normally
1689                        CastExpr * ret = new CastExpr( argExpr, toType->clone() );
1690                        ret->isGenerated = isGenerated;
1691                        return ret;
1692                }
1693        }
1694
1695        void AlternativeFinder::Finder::postvisit( CastExpr *castExpr ) {
1696                Type *& toType = castExpr->get_result();
1697                assert( toType );
1698                toType = resolveTypeof( toType, indexer );
1699                SymTab::validateType( toType, &indexer );
1700                adjustExprType( toType, env, indexer );
1701
1702                AlternativeFinder finder( indexer, env );
1703                finder.targetType = toType;
1704                finder.findWithAdjustment( castExpr->arg );
1705
1706                AltList candidates;
1707                for ( Alternative & alt : finder.alternatives ) {
1708                        AssertionSet needAssertions, haveAssertions;
1709                        OpenVarSet openVars;
1710
1711                        alt.env.extractOpenVars( openVars );
1712
1713                        // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
1714                        // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
1715                        // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
1716                        // to.
1717                        int discardedValues = alt.expr->result->size() - castExpr->result->size();
1718                        if ( discardedValues < 0 ) continue;
1719                        // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1720                        // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1721                        // unification run for side-effects
1722                        unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
1723                                haveAssertions, openVars, indexer );
1724                        Cost thisCost = castCost( alt.expr->result, castExpr->result, indexer,
1725                                alt.env );
1726                        PRINT(
1727                                std::cerr << "working on cast with result: " << castExpr->result << std::endl;
1728                                std::cerr << "and expr type: " << alt.expr->result << std::endl;
1729                                std::cerr << "env: " << alt.env << std::endl;
1730                        )
1731                        if ( thisCost != Cost::infinity ) {
1732                                PRINT(
1733                                        std::cerr << "has finite cost." << std::endl;
1734                                )
1735                                // count one safe conversion for each value that is thrown away
1736                                thisCost.incSafe( discardedValues );
1737                                Alternative newAlt( restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ), alt.env,
1738                                        alt.cost, thisCost );
1739                                inferParameters( needAssertions, haveAssertions, std::move(newAlt), openVars,
1740                                        back_inserter( candidates ) );
1741                        } // if
1742                } // for
1743
1744                // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1745                // cvtCost member to the cost member (since the old cost is now irrelevant).  Thus, calling findMinCost twice
1746                // selects first based on argument cost, then on conversion cost.
1747                AltList minArgCost;
1748                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1749                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1750        }
1751
1752        void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
1753                assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
1754                AlternativeFinder finder( indexer, env );
1755                // don't prune here, since it's guaranteed all alternatives will have the same type
1756                finder.findWithoutPrune( castExpr->get_arg() );
1757                for ( Alternative & alt : finder.alternatives ) {
1758                        alternatives.push_back( Alternative(
1759                                new VirtualCastExpr( alt.expr, castExpr->get_result()->clone() ),
1760                                alt.env, alt.cost ) );
1761                }
1762        }
1763
1764        namespace {
1765                /// Gets name from untyped member expression (member must be NameExpr)
1766                const std::string& get_member_name( UntypedMemberExpr *memberExpr ) {
1767                        NameExpr * nameExpr = dynamic_cast< NameExpr * >( memberExpr->get_member() );
1768                        assert( nameExpr );
1769                        return nameExpr->get_name();
1770                }
1771        }
1772
1773        void AlternativeFinder::Finder::postvisit( UntypedMemberExpr *memberExpr ) {
1774                AlternativeFinder funcFinder( indexer, env );
1775                funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
1776                for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
1777                        // 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
1778                        Cost cost = agg->cost;
1779                        Expression * aggrExpr = agg->expr->clone();
1780                        referenceToRvalueConversion( aggrExpr, cost );
1781
1782                        // find member of the given type
1783                        if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
1784                                addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1785                        } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
1786                                addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1787                        } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
1788                                addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() );
1789                        } // if
1790                } // for
1791        }
1792
1793        void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
1794                alternatives.push_back( Alternative( memberExpr, env, Cost::zero ) );
1795        }
1796
1797        void AlternativeFinder::Finder::postvisit( NameExpr *nameExpr ) {
1798                std::list< SymTab::Indexer::IdData > declList;
1799                indexer.lookupId( nameExpr->name, declList );
1800                PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
1801                for ( auto & data : declList ) {
1802                        Cost cost = Cost::zero;
1803                        Expression * newExpr = data.combine( cost );
1804
1805                        // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
1806                        // can't construct in place and use vector::back
1807                        Alternative newAlt( newExpr, env, Cost::zero, cost );
1808                        PRINT(
1809                                std::cerr << "decl is ";
1810                                data.id->print( std::cerr );
1811                                std::cerr << std::endl;
1812                                std::cerr << "newExpr is ";
1813                                newExpr->print( std::cerr );
1814                                std::cerr << std::endl;
1815                        )
1816                        renameTypes( newAlt.expr );
1817                        addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
1818                        alternatives.push_back( std::move(newAlt) );
1819                } // for
1820        }
1821
1822        void AlternativeFinder::Finder::postvisit( VariableExpr *variableExpr ) {
1823                // not sufficient to clone here, because variable's type may have changed
1824                // since the VariableExpr was originally created.
1825                alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
1826        }
1827
1828        void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
1829                alternatives.push_back( Alternative( constantExpr, env, Cost::zero ) );
1830        }
1831
1832        void AlternativeFinder::Finder::postvisit( SizeofExpr *sizeofExpr ) {
1833                if ( sizeofExpr->get_isType() ) {
1834                        Type * newType = sizeofExpr->get_type()->clone();
1835                        alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1836                } else {
1837                        // find all alternatives for the argument to sizeof
1838                        AlternativeFinder finder( indexer, env );
1839                        finder.find( sizeofExpr->get_expr() );
1840                        // find the lowest cost alternative among the alternatives, otherwise ambiguous
1841                        AltList winners;
1842                        findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1843                        if ( winners.size() != 1 ) {
1844                                SemanticError( sizeofExpr->get_expr(), "Ambiguous expression in sizeof operand: " );
1845                        } // if
1846                        // return the lowest cost alternative for the argument
1847                        Alternative &choice = winners.front();
1848                        referenceToRvalueConversion( choice.expr, choice.cost );
1849                        alternatives.push_back( Alternative( new SizeofExpr( choice.expr ), choice.env, Cost::zero ) );
1850                } // if
1851        }
1852
1853        void AlternativeFinder::Finder::postvisit( AlignofExpr *alignofExpr ) {
1854                if ( alignofExpr->get_isType() ) {
1855                        Type * newType = alignofExpr->get_type()->clone();
1856                        alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1857                } else {
1858                        // find all alternatives for the argument to sizeof
1859                        AlternativeFinder finder( indexer, env );
1860                        finder.find( alignofExpr->get_expr() );
1861                        // find the lowest cost alternative among the alternatives, otherwise ambiguous
1862                        AltList winners;
1863                        findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1864                        if ( winners.size() != 1 ) {
1865                                SemanticError( alignofExpr->get_expr(), "Ambiguous expression in alignof operand: " );
1866                        } // if
1867                        // return the lowest cost alternative for the argument
1868                        Alternative &choice = winners.front();
1869                        referenceToRvalueConversion( choice.expr, choice.cost );
1870                        alternatives.push_back( Alternative( new AlignofExpr( choice.expr ), choice.env, Cost::zero ) );
1871                } // if
1872        }
1873
1874        template< typename StructOrUnionType >
1875        void AlternativeFinder::Finder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
1876                std::list< Declaration* > members;
1877                aggInst->lookup( name, members );
1878                for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1879                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
1880                                alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
1881                                renameTypes( alternatives.back().expr );
1882                        } else {
1883                                assert( false );
1884                        }
1885                }
1886        }
1887
1888        void AlternativeFinder::Finder::postvisit( UntypedOffsetofExpr *offsetofExpr ) {
1889                AlternativeFinder funcFinder( indexer, env );
1890                // xxx - resolveTypeof?
1891                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
1892                        addOffsetof( structInst, offsetofExpr->member );
1893                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
1894                        addOffsetof( unionInst, offsetofExpr->member );
1895                }
1896        }
1897
1898        void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
1899                alternatives.push_back( Alternative( offsetofExpr, env, Cost::zero ) );
1900        }
1901
1902        void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
1903                alternatives.push_back( Alternative( offsetPackExpr, env, Cost::zero ) );
1904        }
1905
1906        namespace {
1907                void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
1908                        // assume no polymorphism
1909                        // assume no implicit conversions
1910                        assert( function->get_parameters().size() == 1 );
1911                        PRINT(
1912                                std::cerr << "resolvAttr: funcDecl is ";
1913                                data.id->print( std::cerr );
1914                                std::cerr << " argType is ";
1915                                argType->print( std::cerr );
1916                                std::cerr << std::endl;
1917                        )
1918                        const SymTab::Indexer & indexer = finder.get_indexer();
1919                        AltList & alternatives = finder.get_alternatives();
1920                        if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1921                                Cost cost = Cost::zero;
1922                                Expression * newExpr = data.combine( cost );
1923                                alternatives.push_back( Alternative( new AttrExpr( newExpr, argType->clone() ), env, Cost::zero, cost ) );
1924                                for ( DeclarationWithType * retVal : function->returnVals ) {
1925                                        alternatives.back().expr->result = retVal->get_type()->clone();
1926                                } // for
1927                        } // if
1928                }
1929        }
1930
1931        void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
1932                // assume no 'pointer-to-attribute'
1933                NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1934                assert( nameExpr );
1935                std::list< SymTab::Indexer::IdData > attrList;
1936                indexer.lookupId( nameExpr->get_name(), attrList );
1937                if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
1938                        for ( auto & data : attrList ) {
1939                                DeclarationWithType * id = data.id;
1940                                // check if the type is function
1941                                if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
1942                                        // assume exactly one parameter
1943                                        if ( function->get_parameters().size() == 1 ) {
1944                                                if ( attrExpr->get_isType() ) {
1945                                                        resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
1946                                                } else {
1947                                                        AlternativeFinder finder( indexer, env );
1948                                                        finder.find( attrExpr->get_expr() );
1949                                                        for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
1950                                                                if ( choice->expr->get_result()->size() == 1 ) {
1951                                                                        resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
1952                                                                } // fi
1953                                                        } // for
1954                                                } // if
1955                                        } // if
1956                                } // if
1957                        } // for
1958                } else {
1959                        for ( auto & data : attrList ) {
1960                                Cost cost = Cost::zero;
1961                                Expression * newExpr = data.combine( cost );
1962                                alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
1963                                renameTypes( alternatives.back().expr );
1964                        } // for
1965                } // if
1966        }
1967
1968        void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
1969                AlternativeFinder firstFinder( indexer, env );
1970                firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
1971                if ( firstFinder.alternatives.empty() ) return;
1972                AlternativeFinder secondFinder( indexer, env );
1973                secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
1974                if ( secondFinder.alternatives.empty() ) return;
1975                for ( const Alternative & first : firstFinder.alternatives ) {
1976                        for ( const Alternative & second : secondFinder.alternatives ) {
1977                                TypeEnvironment compositeEnv;
1978                                compositeEnv.simpleCombine( first.env );
1979                                compositeEnv.simpleCombine( second.env );
1980
1981                                LogicalExpr *newExpr = new LogicalExpr( first.expr, second.expr, logicalExpr->get_isAnd() );
1982                                alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
1983                        }
1984                }
1985        }
1986
1987        void AlternativeFinder::Finder::postvisit( ConditionalExpr *conditionalExpr ) {
1988                // find alternatives for condition
1989                AlternativeFinder firstFinder( indexer, env );
1990                firstFinder.findWithAdjustment( conditionalExpr->arg1 );
1991                if ( firstFinder.alternatives.empty() ) return;
1992                // find alternatives for true expression
1993                AlternativeFinder secondFinder( indexer, env );
1994                secondFinder.findWithAdjustment( conditionalExpr->arg2 );
1995                if ( secondFinder.alternatives.empty() ) return;
1996                // find alterantives for false expression
1997                AlternativeFinder thirdFinder( indexer, env );
1998                thirdFinder.findWithAdjustment( conditionalExpr->arg3 );
1999                if ( thirdFinder.alternatives.empty() ) return;
2000                for ( const Alternative & first : firstFinder.alternatives ) {
2001                        for ( const Alternative & second : secondFinder.alternatives ) {
2002                                for ( const Alternative & third : thirdFinder.alternatives ) {
2003                                        TypeEnvironment compositeEnv;
2004                                        compositeEnv.simpleCombine( first.env );
2005                                        compositeEnv.simpleCombine( second.env );
2006                                        compositeEnv.simpleCombine( third.env );
2007
2008                                        // unify true and false types, then infer parameters to produce new alternatives
2009                                        OpenVarSet openVars;
2010                                        AssertionSet needAssertions, haveAssertions;
2011                                        Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
2012                                        Type* commonType = nullptr;
2013                                        if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
2014                                                ConditionalExpr *newExpr = new ConditionalExpr( first.expr, second.expr, third.expr );
2015                                                newExpr->result = commonType ? commonType : second.expr->result->clone();
2016                                                // convert both options to the conditional result type
2017                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
2018                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
2019                                                newAlt.expr = newExpr;
2020                                                inferParameters( needAssertions, haveAssertions, std::move(newAlt), openVars, back_inserter( alternatives ) );
2021                                        } // if
2022                                } // for
2023                        } // for
2024                } // for
2025        }
2026
2027        void AlternativeFinder::Finder::postvisit( CommaExpr *commaExpr ) {
2028                TypeEnvironment newEnv( env );
2029                Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
2030                AlternativeFinder secondFinder( indexer, newEnv );
2031                secondFinder.findWithAdjustment( commaExpr->get_arg2() );
2032                for ( const Alternative & alt : secondFinder.alternatives ) {
2033                        alternatives.push_back( Alternative( new CommaExpr( newFirstArg, alt.expr ), alt.env, alt.cost ) );
2034                } // for
2035        }
2036
2037        void AlternativeFinder::Finder::postvisit( RangeExpr * rangeExpr ) {
2038                // resolve low and high, accept alternatives whose low and high types unify
2039                AlternativeFinder firstFinder( indexer, env );
2040                firstFinder.findWithAdjustment( rangeExpr->low );
2041                if ( firstFinder.alternatives.empty() ) return;
2042                AlternativeFinder secondFinder( indexer, env );
2043                secondFinder.findWithAdjustment( rangeExpr->high );
2044                if ( secondFinder.alternatives.empty() ) return;
2045                for ( const Alternative & first : firstFinder.alternatives ) {
2046                        for ( const Alternative & second : secondFinder.alternatives ) {
2047                                TypeEnvironment compositeEnv;
2048                                compositeEnv.simpleCombine( first.env );
2049                                compositeEnv.simpleCombine( second.env );
2050                                OpenVarSet openVars;
2051                                AssertionSet needAssertions, haveAssertions;
2052                                Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
2053                                Type* commonType = nullptr;
2054                                if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
2055                                        RangeExpr * newExpr = new RangeExpr( first.expr, second.expr );
2056                                        newExpr->result = commonType ? commonType : first.expr->result->clone();
2057                                        newAlt.expr = newExpr;
2058                                        inferParameters( needAssertions, haveAssertions, std::move(newAlt), openVars, back_inserter( alternatives ) );
2059                                } // if
2060                        } // for
2061                } // for
2062        }
2063
2064        void AlternativeFinder::Finder::postvisit( UntypedTupleExpr *tupleExpr ) {
2065                std::vector< AlternativeFinder > subExprAlternatives;
2066                altFinder.findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
2067                        back_inserter( subExprAlternatives ) );
2068                std::vector< AltList > possibilities;
2069                combos( subExprAlternatives.begin(), subExprAlternatives.end(),
2070                        back_inserter( possibilities ) );
2071                for ( const AltList& alts : possibilities ) {
2072                        std::list< Expression * > exprs;
2073                        makeExprList( alts, exprs );
2074
2075                        TypeEnvironment compositeEnv;
2076                        simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
2077                        alternatives.push_back(
2078                                Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
2079                } // for
2080        }
2081
2082        void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
2083                alternatives.push_back( Alternative( tupleExpr, env, Cost::zero ) );
2084        }
2085
2086        void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
2087                alternatives.push_back( Alternative( impCpCtorExpr, env, Cost::zero ) );
2088        }
2089
2090        void AlternativeFinder::Finder::postvisit( ConstructorExpr * ctorExpr ) {
2091                AlternativeFinder finder( indexer, env );
2092                // don't prune here, since it's guaranteed all alternatives will have the same type
2093                // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
2094                finder.findWithoutPrune( ctorExpr->get_callExpr() );
2095                for ( Alternative & alt : finder.alternatives ) {
2096                        alternatives.push_back( Alternative( new ConstructorExpr( alt.expr ), alt.env, alt.cost ) );
2097                }
2098        }
2099
2100        void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
2101                alternatives.push_back( Alternative( tupleExpr, env, Cost::zero ) );
2102        }
2103
2104        void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
2105                alternatives.push_back( Alternative( tupleAssignExpr, env, Cost::zero ) );
2106        }
2107
2108        void AlternativeFinder::Finder::postvisit( UniqueExpr *unqExpr ) {
2109                AlternativeFinder finder( indexer, env );
2110                finder.findWithAdjustment( unqExpr->get_expr() );
2111                for ( Alternative & alt : finder.alternatives ) {
2112                        // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
2113                        UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr, unqExpr->get_id() );
2114                        alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
2115                }
2116        }
2117
2118        void AlternativeFinder::Finder::postvisit( StmtExpr *stmtExpr ) {
2119                StmtExpr * newStmtExpr = stmtExpr->clone();
2120                ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
2121                // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
2122                alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
2123        }
2124
2125        void AlternativeFinder::Finder::postvisit( UntypedInitExpr *initExpr ) {
2126                // handle each option like a cast
2127                AltList candidates;
2128                PRINT(
2129                        std::cerr << "untyped init expr: " << initExpr << std::endl;
2130                )
2131                // O(N^2) checks of d-types with e-types
2132                for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
2133                        Type * toType = resolveTypeof( initAlt.type->clone(), indexer );
2134                        SymTab::validateType( toType, &indexer );
2135                        adjustExprType( toType, env, indexer );
2136                        // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
2137                        // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
2138                        // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
2139                        AlternativeFinder finder( indexer, env );
2140                        finder.targetType = toType;
2141                        finder.findWithAdjustment( initExpr->expr );
2142                        for ( Alternative & alt : finder.get_alternatives() ) {
2143                                TypeEnvironment newEnv( alt.env );
2144                                AssertionSet needAssertions, haveAssertions;
2145                                OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
2146                                PRINT(
2147                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
2148                                )
2149                                // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
2150                                // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
2151                                // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
2152                                // to.
2153                                int discardedValues = alt.expr->result->size() - toType->size();
2154                                if ( discardedValues < 0 ) continue;
2155                                // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
2156                                // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
2157                                // unification run for side-effects
2158                                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??
2159
2160                                Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
2161                                if ( thisCost != Cost::infinity ) {
2162                                        // count one safe conversion for each value that is thrown away
2163                                        thisCost.incSafe( discardedValues );
2164                                        Alternative newAlt( new InitExpr( restructureCast( alt.expr, toType, true ), initAlt.designation ), newEnv, alt.cost, thisCost );
2165                                        inferParameters( needAssertions, haveAssertions, std::move(newAlt), openVars, back_inserter( candidates ) );
2166                                }
2167                        }
2168                }
2169
2170                // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
2171                // cvtCost member to the cost member (since the old cost is now irrelevant).  Thus, calling findMinCost twice
2172                // selects first based on argument cost, then on conversion cost.
2173                AltList minArgCost;
2174                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
2175                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
2176        }
2177
2178        void AlternativeFinder::Finder::postvisit( InitExpr * ) {
2179                assertf( false, "AlternativeFinder should never see a resolved InitExpr." );
2180        }
2181
2182        void AlternativeFinder::Finder::postvisit( DeletedExpr * ) {
2183                assertf( false, "AlternativeFinder should never see a DeletedExpr." );
2184        }
2185
2186        void AlternativeFinder::Finder::postvisit( GenericExpr * ) {
2187                assertf( false, "_Generic is not yet supported." );
2188        }
2189} // namespace ResolvExpr
2190
2191// Local Variables: //
2192// tab-width: 4 //
2193// mode: c++ //
2194// compile-command: "make install" //
2195// End: //
Note: See TracBrowser for help on using the repository browser.