source: src/ResolvExpr/AlternativeFinder.cc @ 2472a19

new-envwith_gc
Last change on this file since 2472a19 was ff29f08, checked in by Aaron Moss <a3moss@…>, 6 years ago

Merge remote-tracking branch 'origin/master' into with_gc

  • Property mode set to 100644
File size: 73.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 : Peter A. Buhr
12// Last Modified On : Sat Feb 17 11:19:39 2018
13// Update Count     : 33
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 <list>                    // for _List_iterator, list, _List_const_...
22#include <map>                     // for _Rb_tree_iterator, map, _Rb_tree_c...
23#include <memory>                  // for allocator_traits<>::value_type
24#include <utility>                 // for pair
25#include <vector>                  // for vector
26
27#include "Alternative.h"           // for AltList, Alternative
28#include "AlternativeFinder.h"
29#include "Common/SemanticError.h"  // for SemanticError
30#include "Common/utility.h"        // for deleteAll, printAll, CodeLocation
31#include "Cost.h"                  // for Cost, Cost::zero, operator<<, Cost...
32#include "ExplodedActual.h"        // for ExplodedActual
33#include "InitTweak/InitTweak.h"   // for getFunctionName
34#include "RenameVars.h"            // for RenameVars, global_renamer
35#include "ResolveTypeof.h"         // for resolveTypeof
36#include "Resolver.h"              // for resolveStmtExpr
37#include "Common/GC.h"             // for new_static_root
38#include "SymTab/Indexer.h"        // for Indexer
39#include "SymTab/Mangler.h"        // for Mangler
40#include "SymTab/Validate.h"       // for validateType
41#include "SynTree/Constant.h"      // for Constant
42#include "SynTree/Declaration.h"   // for DeclarationWithType, TypeDecl, Dec...
43#include "SynTree/Expression.h"    // for Expression, CastExpr, NameExpr
44#include "SynTree/Initializer.h"   // for SingleInit, operator<<, Designation
45#include "SynTree/SynTree.h"       // for UniqueId
46#include "SynTree/Type.h"          // for Type, FunctionType, PointerType
47#include "Tuples/Explode.h"        // for explode
48#include "Tuples/Tuples.h"         // for isTtype, handleTupleAssignment
49#include "Unify.h"                 // for unify
50#include "typeops.h"               // for adjustExprType, polyCost, castCost
51
52extern bool resolvep;
53#define PRINT( text ) if ( resolvep ) { text }
54//#define DEBUG_COST
55
56using std::move;
57
58/// copies any copyable type
59template<typename T>
60T copy(const T& x) { return x; }
61
62namespace ResolvExpr {
63        struct AlternativeFinder::Finder : public WithShortCircuiting {
64                Finder( AlternativeFinder & altFinder ) : altFinder( altFinder ), indexer( altFinder.indexer ), alternatives( altFinder.alternatives ), env( altFinder.env ), targetType( altFinder.targetType )  {}
65
66                void previsit( BaseSyntaxNode * ) { visit_children = false; }
67
68                void postvisit( ApplicationExpr * applicationExpr );
69                void postvisit( UntypedExpr * untypedExpr );
70                void postvisit( AddressExpr * addressExpr );
71                void postvisit( LabelAddressExpr * labelExpr );
72                void postvisit( CastExpr * castExpr );
73                void postvisit( VirtualCastExpr * castExpr );
74                void postvisit( UntypedMemberExpr * memberExpr );
75                void postvisit( MemberExpr * memberExpr );
76                void postvisit( NameExpr * variableExpr );
77                void postvisit( VariableExpr * variableExpr );
78                void postvisit( ConstantExpr * constantExpr );
79                void postvisit( SizeofExpr * sizeofExpr );
80                void postvisit( AlignofExpr * alignofExpr );
81                void postvisit( UntypedOffsetofExpr * offsetofExpr );
82                void postvisit( OffsetofExpr * offsetofExpr );
83                void postvisit( OffsetPackExpr * offsetPackExpr );
84                void postvisit( AttrExpr * attrExpr );
85                void postvisit( LogicalExpr * logicalExpr );
86                void postvisit( ConditionalExpr * conditionalExpr );
87                void postvisit( CommaExpr * commaExpr );
88                void postvisit( ImplicitCopyCtorExpr  * impCpCtorExpr );
89                void postvisit( ConstructorExpr  * ctorExpr );
90                void postvisit( RangeExpr  * rangeExpr );
91                void postvisit( UntypedTupleExpr * tupleExpr );
92                void postvisit( TupleExpr * tupleExpr );
93                void postvisit( TupleIndexExpr * tupleExpr );
94                void postvisit( TupleAssignExpr * tupleExpr );
95                void postvisit( UniqueExpr * unqExpr );
96                void postvisit( StmtExpr * stmtExpr );
97                void postvisit( UntypedInitExpr * initExpr );
98                void postvisit( InitExpr * initExpr );
99                void postvisit( DeletedExpr * delExpr );
100
101                /// Adds alternatives for anonymous members
102                void addAnonConversions( const Alternative & alt );
103                /// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
104                template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name );
105                /// Adds alternatives for member expressions where the left side has tuple type
106                void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
107                /// Adds alternatives for offsetof expressions, given the base type and name of the member
108                template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
109                /// Takes a final result and checks if its assertions can be satisfied
110                template<typename OutputIterator>
111                void validateFunctionAlternative( const Alternative &func, ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out );
112                /// Finds matching alternatives for a function, given a set of arguments
113                template<typename OutputIterator>
114                void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
115                /// Checks if assertion parameters match for a new alternative
116                template< typename OutputIterator >
117                void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
118        private:
119                AlternativeFinder & altFinder;
120                const SymTab::Indexer &indexer;
121                AltList & alternatives;
122                const TypeEnvironment &env;
123                Type *& targetType;
124        };
125
126        Cost sumCost( const AltList &in ) {
127                Cost total = Cost::zero;
128                for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
129                        total += i->cost;
130                }
131                return total;
132        }
133
134        void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) {
135                Indenter indent = { Indenter::tabsize, indentAmt };
136                for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
137                        i->print( os, indent );
138                        os << std::endl;
139                }
140        }
141
142        namespace {
143                void makeExprList( const AltList &in, std::list< Expression* > &out ) {
144                        for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
145                                out.push_back( i->expr->clone() );
146                        }
147                }
148
149                struct PruneStruct {
150                        bool isAmbiguous;
151                        AltList::iterator candidate;
152                        PruneStruct() {}
153                        PruneStruct( AltList::iterator candidate ): isAmbiguous( false ), candidate( candidate ) {}
154                };
155
156                /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations
157                template< typename InputIterator, typename OutputIterator >
158                void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) {
159                        // select the alternatives that have the minimum conversion cost for a particular set of result types
160                        std::map< std::string, PruneStruct > selected;
161                        for ( AltList::iterator candidate = begin; candidate != end; ++candidate ) {
162                                PruneStruct current( candidate );
163                                std::string mangleName;
164                                {
165                                        Type * newType = candidate->expr->get_result()->clone();
166                                        candidate->env.apply( newType );
167                                        mangleName = SymTab::Mangler::mangle( newType );
168                                }
169                                std::map< std::string, PruneStruct >::iterator mapPlace = selected.find( mangleName );
170                                if ( mapPlace != selected.end() ) {
171                                        if ( candidate->cost < mapPlace->second.candidate->cost ) {
172                                                PRINT(
173                                                        std::cerr << "cost " << candidate->cost << " beats " << mapPlace->second.candidate->cost << std::endl;
174                                                )
175                                                selected[ mangleName ] = current;
176                                        } else if ( candidate->cost == mapPlace->second.candidate->cost ) {
177                                                PRINT(
178                                                        std::cerr << "marking ambiguous" << std::endl;
179                                                )
180                                                mapPlace->second.isAmbiguous = true;
181                                        } else {
182                                                PRINT(
183                                                        std::cerr << "cost " << candidate->cost << " loses to " << mapPlace->second.candidate->cost << std::endl;
184                                                )
185                                        }
186                                } else {
187                                        selected[ mangleName ] = current;
188                                }
189                        }
190
191                        // accept the alternatives that were unambiguous
192                        for ( std::map< std::string, PruneStruct >::iterator target = selected.begin(); target != selected.end(); ++target ) {
193                                if ( ! target->second.isAmbiguous ) {
194                                        Alternative &alt = *target->second.candidate;
195                                        alt.env.applyFree( alt.expr->get_result() );
196                                        *out++ = alt;
197                                }
198                        }
199                }
200
201                void renameTypes( Expression *expr ) {
202                        renameTyVars( expr->result );
203                }
204        } // namespace
205
206        void referenceToRvalueConversion( Expression *& expr, Cost & cost ) {
207                if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
208                        // cast away reference from expr
209                        expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
210                        cost.incReference();
211                }
212        }
213
214        template< typename InputIterator, typename OutputIterator >
215        void AlternativeFinder::findSubExprs( InputIterator begin, InputIterator end, OutputIterator out ) {
216                while ( begin != end ) {
217                        AlternativeFinder finder( indexer, env );
218                        finder.findWithAdjustment( *begin );
219                        // XXX  either this
220                        //Designators::fixDesignations( finder, (*begin++)->get_argName() );
221                        // or XXX this
222                        begin++;
223                        PRINT(
224                                std::cerr << "findSubExprs" << std::endl;
225                                printAlts( finder.alternatives, std::cerr );
226                        )
227                        *out++ = finder;
228                }
229        }
230
231        AlternativeFinder::AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env )
232                : indexer( indexer ), env( env ) {
233        }
234
235        void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
236                PassVisitor<Finder> finder( *this );
237                expr->accept( finder );
238                if ( failFast && alternatives.empty() ) {
239                        PRINT(
240                                std::cerr << "No reasonable alternatives for expression " << expr << std::endl;
241                        )
242                        SemanticError( expr, "No reasonable alternatives for expression " );
243                }
244                if ( prune ) {
245                        auto oldsize = alternatives.size();
246                        PRINT(
247                                std::cerr << "alternatives before prune:" << std::endl;
248                                printAlts( alternatives, std::cerr );
249                        )
250                        AltList pruned;
251                        pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) );
252                        if ( failFast && pruned.empty() ) {
253                                std::ostringstream stream;
254                                AltList winners;
255                                findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
256                                stream << "Cannot choose between " << winners.size() << " alternatives for expression\n";
257                                expr->print( stream );
258                                stream << " Alternatives are:\n";
259                                printAlts( winners, stream, 1 );
260                                SemanticError( expr->location, stream.str() );
261                        }
262                        alternatives = move(pruned);
263                        PRINT(
264                                std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
265                        )
266                        PRINT(
267                                std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl;
268                        )
269                }
270                // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
271                for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
272                        if ( adjust ) {
273                                adjustExprType( i->expr->get_result(), i->env, indexer );
274                        }
275                }
276
277                // Central location to handle gcc extension keyword, etc. for all expression types.
278                for ( Alternative &iter: alternatives ) {
279                        iter.expr->set_extension( expr->get_extension() );
280                        iter.expr->location = expr->location;
281                } // for
282        }
283
284        void AlternativeFinder::findWithAdjustment( Expression *expr ) {
285                find( expr, true );
286        }
287
288        void AlternativeFinder::findWithoutPrune( Expression * expr ) {
289                find( expr, true, false );
290        }
291
292        void AlternativeFinder::maybeFind( Expression * expr ) {
293                find( expr, true, true, false );
294        }
295
296        void AlternativeFinder::Finder::addAnonConversions( const Alternative & alt ) {
297                // adds anonymous member interpretations whenever an aggregate value type is seen.
298                // 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
299                Expression* aggrExpr = alt.expr->clone();
300                alt.env.apply( aggrExpr->get_result() );
301                Type * aggrType = aggrExpr->get_result();
302                if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
303                        aggrType = aggrType->stripReferences();
304                        aggrExpr = new CastExpr{ aggrExpr, aggrType->clone() };
305                }
306
307                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
308                        addAggMembers( structInst, aggrExpr, alt.cost+Cost::safe, alt.env, "" );
309                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
310                        addAggMembers( unionInst, aggrExpr, alt.cost+Cost::safe, alt.env, "" );
311                } // if
312        }
313
314        template< typename StructOrUnionType >
315        void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name ) {
316                std::list< Declaration* > members;
317                aggInst->lookup( name, members );
318
319                for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
320                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
321                                alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) );
322                                renameTypes( alternatives.back().expr );
323                                addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
324                        } else {
325                                assert( false );
326                        }
327                }
328        }
329
330        void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
331                if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
332                        // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
333                        // xxx - this should be improved by memoizing the value of constant exprs
334                        // during parsing and reusing that information here.
335                        std::stringstream ss( constantExpr->get_constant()->get_value() );
336                        int val = 0;
337                        std::string tmp;
338                        if ( ss >> val && ! (ss >> tmp) ) {
339                                if ( val >= 0 && (unsigned int)val < tupleType->size() ) {
340                                        alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
341                                } // if
342                        } // if
343                } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {
344                        // xxx - temporary hack until 0/1 are int constants
345                        if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {
346                                std::stringstream ss( nameExpr->get_name() );
347                                int val;
348                                ss >> val;
349                                alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
350                        }
351                } // if
352        }
353
354        void AlternativeFinder::Finder::postvisit( ApplicationExpr *applicationExpr ) {
355                alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
356        }
357
358        Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
359                PRINT(
360                        std::cerr << std::endl << "converting ";
361                        actualType->print( std::cerr, 8 );
362                        std::cerr << std::endl << " to ";
363                        formalType->print( std::cerr, 8 );
364                        std::cerr << std::endl << "environment is: ";
365                        env.print( std::cerr, 8 );
366                        std::cerr << std::endl;
367                )
368                Cost convCost = conversionCost( actualType, formalType, indexer, env );
369                PRINT(
370                        std::cerr << std::endl << "cost is " << convCost << std::endl;
371                )
372                if ( convCost == Cost::infinity ) {
373                        return convCost;
374                }
375                convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) );
376                PRINT(
377                        std::cerr << "cost with polycost is " << convCost << std::endl;
378                )
379                return convCost;
380        }
381
382        Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
383                Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
384
385                // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion.
386                // ignore poly cost for now, since this requires resolution of the cast to infer parameters and this
387                // does not currently work for the reason stated below.
388                Cost tmpCost = convCost;
389                tmpCost.incPoly( -tmpCost.get_polyCost() );
390                if ( tmpCost != Cost::zero ) {
391                        Type *newType = formalType->clone();
392                        env.apply( newType );
393                        actualExpr = new CastExpr( actualExpr, newType );
394                        // 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
395                        // inconsistent, once this is fixed it should be possible to resolve the cast.
396                        // 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.
397
398                        // AlternativeFinder finder( indexer, env );
399                        // finder.findWithAdjustment( actualExpr );
400                        // assertf( finder.get_alternatives().size() > 0, "Somehow castable expression failed to find alternatives." );
401                        // assertf( finder.get_alternatives().size() == 1, "Somehow got multiple alternatives for known cast expression." );
402                        // Alternative & alt = finder.get_alternatives().front();
403                        // delete actualExpr;
404                        // actualExpr = alt.expr->clone();
405                }
406                return convCost;
407        }
408
409        Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
410                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr );
411                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
412                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
413
414                Cost convCost = Cost::zero;
415                std::list< DeclarationWithType* >& formals = function->get_parameters();
416                std::list< DeclarationWithType* >::iterator formal = formals.begin();
417                std::list< Expression* >& actuals = appExpr->get_args();
418
419                for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
420                        Type * actualType = (*actualExpr)->get_result();
421                        PRINT(
422                                std::cerr << "actual expression:" << std::endl;
423                                (*actualExpr)->print( std::cerr, 8 );
424                                std::cerr << "--- results are" << std::endl;
425                                actualType->print( std::cerr, 8 );
426                        )
427                        if ( formal == formals.end() ) {
428                                if ( function->get_isVarArgs() ) {
429                                        convCost.incUnsafe();
430                                        PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
431                                        // convert reference-typed expressions to value-typed expressions
432                                        referenceToRvalueConversion( *actualExpr, convCost );
433                                        continue;
434                                } else {
435                                        return Cost::infinity;
436                                }
437                        }
438                        Type * formalType = (*formal)->get_type();
439                        convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
440                        ++formal; // can't be in for-loop update because of the continue
441                }
442                if ( formal != formals.end() ) {
443                        return Cost::infinity;
444                }
445
446                for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
447                        convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
448                }
449
450                return convCost;
451        }
452
453        /// Adds type variables to the open variable set and marks their assertions
454        void makeUnifiableVars( Type *type, OpenVarSet &unifiableVars, AssertionSet &needAssertions ) {
455                for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
456                        unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar };
457                        for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->assertions.begin(); assert != (*tyvar)->assertions.end(); ++assert ) {
458                                needAssertions[ *assert ].isUsed = true;
459                        }
460///     needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
461                }
462        }
463
464        // /// Map of declaration uniqueIds (intended to be the assertions in an AssertionSet) to their parents and the number of times they've been included
465        //typedef std::unordered_map< UniqueId, std::unordered_map< UniqueId, unsigned > > AssertionParentSet;
466
467        static const int recursionLimit = /*10*/ 4;  ///< Limit to depth of recursion satisfaction
468        //static const unsigned recursionParentLimit = 1;  ///< Limit to the number of times an assertion can recursively use itself
469
470        void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
471                for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
472                        if ( i->second.isUsed ) {
473                                indexer.addId( i->first );
474                        }
475                }
476        }
477
478        template< typename ForwardIterator, typename OutputIterator >
479        void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/
480                                                 int level, const SymTab::Indexer &indexer, OutputIterator out ) {
481                if ( begin == end ) {
482                        if ( newNeed.empty() ) {
483                                PRINT(
484                                        std::cerr << "all assertions satisfied, output alternative: ";
485                                        newAlt.print( std::cerr );
486                                        std::cerr << std::endl;
487                                );
488                                *out++ = newAlt;
489                                return;
490                        } else if ( level >= recursionLimit ) {
491                                SemanticError( newAlt.expr->location, "Too many recursive assertions" );
492                        } else {
493                                AssertionSet newerNeed;
494                                PRINT(
495                                        std::cerr << "recursing with new set:" << std::endl;
496                                        printAssertionSet( newNeed, std::cerr, 8 );
497                                )
498                                inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, /*needParents,*/ level+1, indexer, out );
499                                return;
500                        }
501                }
502
503                ForwardIterator cur = begin++;
504                if ( ! cur->second.isUsed ) {
505                        inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out );
506                        return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
507                }
508                DeclarationWithType *curDecl = cur->first;
509
510                PRINT(
511                        std::cerr << "inferRecursive: assertion is ";
512                        curDecl->print( std::cerr );
513                        std::cerr << std::endl;
514                )
515                std::list< SymTab::Indexer::IdData > candidates;
516                decls.lookupId( curDecl->get_name(), candidates );
517///   if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
518                for ( const auto & data : candidates ) {
519                        DeclarationWithType * candidate = data.id;
520                        PRINT(
521                                std::cerr << "inferRecursive: candidate is ";
522                                candidate->print( std::cerr );
523                                std::cerr << std::endl;
524                        )
525
526                        AssertionSet newHave, newerNeed( newNeed );
527                        TypeEnvironment newEnv( newAlt.env );
528                        OpenVarSet newOpenVars( openVars );
529                        Type *adjType = candidate->get_type()->clone();
530                        adjustExprType( adjType, newEnv, indexer );
531                        renameTyVars( adjType );
532                        PRINT(
533                                std::cerr << "unifying ";
534                                curDecl->get_type()->print( std::cerr );
535                                std::cerr << " with ";
536                                adjType->print( std::cerr );
537                                std::cerr << std::endl;
538                        )
539                        if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
540                                PRINT(
541                                        std::cerr << "success!" << std::endl;
542                                )
543                                SymTab::Indexer newDecls( decls );
544                                addToIndexer( newHave, newDecls );
545                                Alternative newerAlt( newAlt );
546                                newerAlt.env = newEnv;
547                                assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
548
549                                // everything with an empty idChain was pulled in by the current assertion.
550                                // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
551                                for ( auto & a : newerNeed ) {
552                                        if ( a.second.idChain.empty() ) {
553                                                a.second.idChain = cur->second.idChain;
554                                                a.second.idChain.push_back( curDecl->get_uniqueId() );
555                                        }
556                                }
557
558                                //AssertionParentSet newNeedParents( needParents );
559                                // skip repeatingly-self-recursive assertion satisfaction
560                                // DOESN'T WORK: grandchild nodes conflict with their cousins
561                                //if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue;
562
563                                Expression *varExpr = data.combine( newerAlt.cvtCost );
564                                varExpr->set_result( adjType->clone() );
565                                PRINT(
566                                        std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
567                                        curDecl->print( std::cerr );
568                                        std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
569                                        candidate->print( std::cerr );
570                                        std::cerr << std::endl;
571                                )
572                                // 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).
573                                InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
574                                for ( UniqueId id : cur->second.idChain ) {
575                                        inferParameters = (*inferParameters)[ id ].inferParams.get();
576                                }
577                                // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
578                                (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
579                                inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out );
580                        }
581                }
582        }
583
584        template< typename OutputIterator >
585        void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
586//      PRINT(
587//          std::cerr << "inferParameters: assertions needed are" << std::endl;
588//          printAll( need, std::cerr, 8 );
589//          )
590                SymTab::Indexer decls( indexer );
591                // PRINT(
592                //      std::cerr << "============= original indexer" << std::endl;
593                //      indexer.print( std::cerr );
594                //      std::cerr << "============= new indexer" << std::endl;
595                //      decls.print( std::cerr );
596                // )
597                addToIndexer( have, decls );
598                AssertionSet newNeed;
599                //AssertionParentSet needParents;
600                PRINT(
601                        std::cerr << "env is: " << std::endl;
602                        newAlt.env.print( std::cerr, 0 );
603                        std::cerr << std::endl;
604                )
605
606                inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, /*needParents,*/ 0, indexer, out );
607//      PRINT(
608//          std::cerr << "declaration 14 is ";
609//          Declaration::declFromId
610//          *out++ = newAlt;
611//          )
612        }
613
614        /// Gets a default value from an initializer, nullptr if not present
615        ConstantExpr* getDefaultValue( Initializer* init ) {
616                if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
617                        if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->get_value() ) ) {
618                                return dynamic_cast<ConstantExpr*>( ce->get_arg() );
619                        }
620                }
621                return nullptr;
622        }
623
624        /// State to iteratively build a match of parameter expressions to arguments
625        struct ArgPack {
626                std::size_t parent;                ///< Index of parent pack
627                Expression* expr;                  ///< The argument stored here
628                Cost cost;                         ///< The cost of this argument
629                TypeEnvironment env;               ///< Environment for this pack
630                AssertionSet need;                 ///< Assertions outstanding for this pack
631                AssertionSet have;                 ///< Assertions found for this pack
632                OpenVarSet openVars;               ///< Open variables for this pack
633                unsigned nextArg;                  ///< Index of next argument in arguments list
634                unsigned tupleStart;               ///< Number of tuples that start at this index
635                unsigned nextExpl;                 ///< Index of next exploded element
636                unsigned explAlt;                  ///< Index of alternative for nextExpl > 0
637
638                ArgPack()
639                        : parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0),
640                          tupleStart(0), nextExpl(0), explAlt(0) {}
641
642                ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
643                                const OpenVarSet& openVars)
644                        : parent(0), expr(), cost(Cost::zero), env(env), need(need), have(have),
645                          openVars(openVars), nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
646
647                ArgPack(std::size_t parent, Expression* expr, TypeEnvironment&& env, AssertionSet&& need,
648                                AssertionSet&& have, OpenVarSet&& openVars, unsigned nextArg,
649                                unsigned tupleStart = 0, Cost cost = Cost::zero, unsigned nextExpl = 0,
650                                unsigned explAlt = 0 )
651                        : parent(parent), expr(expr->clone()), cost(cost), env(move(env)), need(move(need)),
652                          have(move(have)), openVars(move(openVars)), nextArg(nextArg), tupleStart(tupleStart),
653                          nextExpl(nextExpl), explAlt(explAlt) {}
654
655                ArgPack(const ArgPack& o, TypeEnvironment&& env, AssertionSet&& need, AssertionSet&& have,
656                                OpenVarSet&& openVars, unsigned nextArg, Cost added )
657                        : parent(o.parent), expr(o.expr ? o.expr->clone() : nullptr), cost(o.cost + added),
658                          env(move(env)), need(move(need)), have(move(have)), openVars(move(openVars)),
659                          nextArg(nextArg), tupleStart(o.tupleStart), nextExpl(0), explAlt(0) {}
660
661                /// true iff this pack is in the middle of an exploded argument
662                bool hasExpl() const { return nextExpl > 0; }
663
664                /// Gets the list of exploded alternatives for this pack
665                const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
666                        return args[nextArg-1][explAlt];
667                }
668
669                /// Ends a tuple expression, consolidating the appropriate actuals
670                void endTuple( const std::vector<ArgPack>& packs ) {
671                        // add all expressions in tuple to list, summing cost
672                        std::list<Expression*> exprs;
673                        const ArgPack* pack = this;
674                        if ( expr ) { exprs.push_front( expr ); }
675                        while ( pack->tupleStart == 0 ) {
676                                pack = &packs[pack->parent];
677                                exprs.push_front( pack->expr->clone() );
678                                cost += pack->cost;
679                        }
680                        // reset pack to appropriate tuple
681                        expr = new TupleExpr{ exprs };
682                        tupleStart = pack->tupleStart - 1;
683                        parent = pack->parent;
684                }
685        };
686
687        /// Instantiates an argument to match a formal, returns false if no results left
688        bool instantiateArgument( Type* formalType, Initializer* initializer,
689                        const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
690                        const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
691                if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
692                        // formalType is a TupleType - group actuals into a TupleExpr
693                        ++nTuples;
694                        for ( Type* type : *tupleType ) {
695                                // xxx - dropping initializer changes behaviour from previous, but seems correct
696                                if ( ! instantiateArgument(
697                                                type, nullptr, args, results, genStart, indexer, nTuples ) )
698                                        return false;
699                                nTuples = 0;
700                        }
701                        // re-consititute tuples for final generation
702                        for ( auto i = genStart; i < results.size(); ++i ) {
703                                results[i].endTuple( results );
704                        }
705                        return true;
706                } else if ( TypeInstType* ttype = Tuples::isTtype( formalType ) ) {
707                        // formalType is a ttype, consumes all remaining arguments
708                        // xxx - mixing default arguments with variadic??
709
710                        // completed tuples; will be spliced to end of results to finish
711                        std::vector<ArgPack> finalResults{};
712
713                        // iterate until all results completed
714                        std::size_t genEnd;
715                        ++nTuples;
716                        do {
717                                genEnd = results.size();
718
719                                // add another argument to results
720                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
721                                        auto nextArg = results[i].nextArg;
722
723                                        // use next element of exploded tuple if present
724                                        if ( results[i].hasExpl() ) {
725                                                const ExplodedActual& expl = results[i].getExpl( args );
726
727                                                unsigned nextExpl = results[i].nextExpl + 1;
728                                                if ( nextExpl == expl.exprs.size() ) {
729                                                        nextExpl = 0;
730                                                }
731
732                                                results.emplace_back(
733                                                        i, expl.exprs[results[i].nextExpl], copy(results[i].env),
734                                                        copy(results[i].need), copy(results[i].have),
735                                                        copy(results[i].openVars), nextArg, nTuples, Cost::zero, nextExpl,
736                                                        results[i].explAlt );
737
738                                                continue;
739                                        }
740
741                                        // finish result when out of arguments
742                                        if ( nextArg >= args.size() ) {
743                                                ArgPack newResult{
744                                                        results[i].env, results[i].need, results[i].have,
745                                                        results[i].openVars };
746                                                newResult.nextArg = nextArg;
747                                                Type* argType;
748
749                                                if ( nTuples > 0 || ! results[i].expr ) {
750                                                        // first iteration or no expression to clone,
751                                                        // push empty tuple expression
752                                                        newResult.parent = i;
753                                                        std::list<Expression*> emptyList;
754                                                        newResult.expr = new TupleExpr{ emptyList };
755                                                        argType = newResult.expr->get_result();
756                                                } else {
757                                                        // clone result to collect tuple
758                                                        newResult.parent = results[i].parent;
759                                                        newResult.cost = results[i].cost;
760                                                        newResult.tupleStart = results[i].tupleStart;
761                                                        newResult.expr = results[i].expr->clone();
762                                                        argType = newResult.expr->get_result();
763
764                                                        if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
765                                                                // the case where a ttype value is passed directly is special,
766                                                                // e.g. for argument forwarding purposes
767                                                                // xxx - what if passing multiple arguments, last of which is
768                                                                //       ttype?
769                                                                // xxx - what would happen if unify was changed so that unifying
770                                                                //       tuple
771                                                                // types flattened both before unifying lists? then pass in
772                                                                // TupleType (ttype) below.
773                                                                --newResult.tupleStart;
774                                                        } else {
775                                                                // collapse leftover arguments into tuple
776                                                                newResult.endTuple( results );
777                                                                argType = newResult.expr->get_result();
778                                                        }
779                                                }
780
781                                                // check unification for ttype before adding to final
782                                                if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have,
783                                                                newResult.openVars, indexer ) ) {
784                                                        finalResults.push_back( move(newResult) );
785                                                }
786
787                                                continue;
788                                        }
789
790                                        // add each possible next argument
791                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
792                                                const ExplodedActual& expl = args[nextArg][j];
793
794                                                // fresh copies of parent parameters for this iteration
795                                                TypeEnvironment env = results[i].env;
796                                                OpenVarSet openVars = results[i].openVars;
797
798                                                env.addActual( expl.env, openVars );
799
800                                                // skip empty tuple arguments by (near-)cloning parent into next gen
801                                                if ( expl.exprs.empty() ) {
802                                                        results.emplace_back(
803                                                                results[i], move(env), copy(results[i].need),
804                                                                copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
805
806                                                        continue;
807                                                }
808
809                                                // add new result
810                                                results.emplace_back(
811                                                        i, expl.exprs.front(), move(env), copy(results[i].need),
812                                                        copy(results[i].have), move(openVars), nextArg + 1,
813                                                        nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
814                                        }
815                                }
816
817                                // reset for next round
818                                genStart = genEnd;
819                                nTuples = 0;
820                        } while ( genEnd != results.size() );
821
822                        // splice final results onto results
823                        for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
824                                results.push_back( move(finalResults[i]) );
825                        }
826                        return ! finalResults.empty();
827                }
828
829                // iterate each current subresult
830                std::size_t genEnd = results.size();
831                for ( std::size_t i = genStart; i < genEnd; ++i ) {
832                        auto nextArg = results[i].nextArg;
833
834                        // use remainder of exploded tuple if present
835                        if ( results[i].hasExpl() ) {
836                                const ExplodedActual& expl = results[i].getExpl( args );
837                                Expression* expr = expl.exprs[results[i].nextExpl];
838
839                                TypeEnvironment env = results[i].env;
840                                AssertionSet need = results[i].need, have = results[i].have;
841                                OpenVarSet openVars = results[i].openVars;
842
843                                Type* actualType = expr->get_result();
844
845                                PRINT(
846                                        std::cerr << "formal type is ";
847                                        formalType->print( std::cerr );
848                                        std::cerr << std::endl << "actual type is ";
849                                        actualType->print( std::cerr );
850                                        std::cerr << std::endl;
851                                )
852
853                                if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
854                                        unsigned nextExpl = results[i].nextExpl + 1;
855                                        if ( nextExpl == expl.exprs.size() ) {
856                                                nextExpl = 0;
857                                        }
858
859                                        results.emplace_back(
860                                                i, expr, move(env), move(need), move(have), move(openVars), nextArg,
861                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
862                                }
863
864                                continue;
865                        }
866
867                        // use default initializers if out of arguments
868                        if ( nextArg >= args.size() ) {
869                                if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
870                                        if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
871                                                TypeEnvironment env = results[i].env;
872                                                AssertionSet need = results[i].need, have = results[i].have;
873                                                OpenVarSet openVars = results[i].openVars;
874
875                                                if ( unify( formalType, cnst->get_type(), env, need, have, openVars,
876                                                                indexer ) ) {
877                                                        results.emplace_back(
878                                                                i, cnstExpr, move(env), move(need), move(have),
879                                                                move(openVars), nextArg, nTuples );
880                                                }
881                                        }
882                                }
883
884                                continue;
885                        }
886
887                        // Check each possible next argument
888                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
889                                const ExplodedActual& expl = args[nextArg][j];
890
891                                // fresh copies of parent parameters for this iteration
892                                TypeEnvironment env = results[i].env;
893                                AssertionSet need = results[i].need, have = results[i].have;
894                                OpenVarSet openVars = results[i].openVars;
895
896                                env.addActual( expl.env, openVars );
897
898                                // skip empty tuple arguments by (near-)cloning parent into next gen
899                                if ( expl.exprs.empty() ) {
900                                        results.emplace_back(
901                                                results[i], move(env), move(need), move(have), move(openVars),
902                                                nextArg + 1, expl.cost );
903
904                                        continue;
905                                }
906
907                                // consider only first exploded actual
908                                Expression* expr = expl.exprs.front();
909                                Type* actualType = expr->get_result()->clone();
910
911                                PRINT(
912                                        std::cerr << "formal type is ";
913                                        formalType->print( std::cerr );
914                                        std::cerr << std::endl << "actual type is ";
915                                        actualType->print( std::cerr );
916                                        std::cerr << std::endl;
917                                )
918
919                                // attempt to unify types
920                                if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
921                                        // add new result
922                                        results.emplace_back(
923                                                i, expr, move(env), move(need), move(have), move(openVars), nextArg + 1,
924                                                nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
925                                }
926                        }
927                }
928
929                // reset for next parameter
930                genStart = genEnd;
931
932                return genEnd != results.size();
933        }
934
935        template<typename OutputIterator>
936        void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func, ArgPack& result,
937                        const std::vector<ArgPack>& results, OutputIterator out ) {
938                ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
939                // sum cost and accumulate actuals
940                std::list<Expression*>& args = appExpr->get_args();
941                Cost cost = func.cost;
942                const ArgPack* pack = &result;
943                while ( pack->expr ) {
944                        args.push_front( pack->expr->clone() );
945                        cost += pack->cost;
946                        pack = &results[pack->parent];
947                }
948                // build and validate new alternative
949                Alternative newAlt( appExpr, result.env, cost );
950                PRINT(
951                        std::cerr << "instantiate function success: " << appExpr << std::endl;
952                        std::cerr << "need assertions:" << std::endl;
953                        printAssertionSet( result.need, std::cerr, 8 );
954                )
955                inferParameters( result.need, result.have, newAlt, result.openVars, out );
956        }
957
958        template<typename OutputIterator>
959        void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
960                        FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
961                OpenVarSet funcOpenVars;
962                AssertionSet funcNeed, funcHave;
963                TypeEnvironment funcEnv( func.env );
964                makeUnifiableVars( funcType, funcOpenVars, funcNeed );
965                // add all type variables as open variables now so that those not used in the parameter
966                // list are still considered open.
967                funcEnv.add( funcType->get_forall() );
968
969                if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
970                        // attempt to narrow based on expected target type
971                        Type * returnType = funcType->get_returnVals().front()->get_type();
972                        if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
973                                        indexer ) ) {
974                                // unification failed, don't pursue this function alternative
975                                return;
976                        }
977                }
978
979                // iteratively build matches, one parameter at a time
980                std::vector<ArgPack> results;
981                results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } );
982                std::size_t genStart = 0;
983
984                for ( DeclarationWithType* formal : funcType->get_parameters() ) {
985                        ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
986                        if ( ! instantiateArgument(
987                                        obj->get_type(), obj->get_init(), args, results, genStart, indexer ) )
988                                return;
989                }
990
991                if ( funcType->get_isVarArgs() ) {
992                        // append any unused arguments to vararg pack
993                        std::size_t genEnd;
994                        do {
995                                genEnd = results.size();
996
997                                // iterate results
998                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
999                                        auto nextArg = results[i].nextArg;
1000
1001                                        // use remainder of exploded tuple if present
1002                                        if ( results[i].hasExpl() ) {
1003                                                const ExplodedActual& expl = results[i].getExpl( args );
1004
1005                                                unsigned nextExpl = results[i].nextExpl + 1;
1006                                                if ( nextExpl == expl.exprs.size() ) {
1007                                                        nextExpl = 0;
1008                                                }
1009
1010                                                results.emplace_back(
1011                                                        i, expl.exprs[results[i].nextExpl], copy(results[i].env),
1012                                                        copy(results[i].need), copy(results[i].have),
1013                                                        copy(results[i].openVars), nextArg, 0, Cost::zero, nextExpl,
1014                                                        results[i].explAlt );
1015
1016                                                continue;
1017                                        }
1018
1019                                        // finish result when out of arguments
1020                                        if ( nextArg >= args.size() ) {
1021                                                validateFunctionAlternative( func, results[i], results, out );
1022
1023                                                continue;
1024                                        }
1025
1026                                        // add each possible next argument
1027                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1028                                                const ExplodedActual& expl = args[nextArg][j];
1029
1030                                                // fresh copies of parent parameters for this iteration
1031                                                TypeEnvironment env = results[i].env;
1032                                                OpenVarSet openVars = results[i].openVars;
1033
1034                                                env.addActual( expl.env, openVars );
1035
1036                                                // skip empty tuple arguments by (near-)cloning parent into next gen
1037                                                if ( expl.exprs.empty() ) {
1038                                                        results.emplace_back(
1039                                                                results[i], move(env), copy(results[i].need),
1040                                                                copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
1041
1042                                                        continue;
1043                                                }
1044
1045                                                // add new result
1046                                                results.emplace_back(
1047                                                        i, expl.exprs.front(), move(env), copy(results[i].need),
1048                                                        copy(results[i].have), move(openVars), nextArg + 1, 0,
1049                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1050                                        }
1051                                }
1052
1053                                genStart = genEnd;
1054                        } while ( genEnd != results.size() );
1055                } else {
1056                        // filter out results that don't use all the arguments
1057                        for ( std::size_t i = genStart; i < results.size(); ++i ) {
1058                                ArgPack& result = results[i];
1059                                if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
1060                                        validateFunctionAlternative( func, result, results, out );
1061                                }
1062                        }
1063                }
1064        }
1065
1066        void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
1067                AlternativeFinder funcFinder( indexer, env );
1068                funcFinder.findWithAdjustment( untypedExpr->get_function() );
1069                // if there are no function alternatives, then proceeding is a waste of time.
1070                if ( funcFinder.alternatives.empty() ) return;
1071
1072                std::vector< AlternativeFinder > argAlternatives;
1073                altFinder.findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
1074                        back_inserter( argAlternatives ) );
1075
1076                // take care of possible tuple assignments
1077                // if not tuple assignment, assignment is taken care of as a normal function call
1078                Tuples::handleTupleAssignment( altFinder, untypedExpr, argAlternatives );
1079
1080                // find function operators
1081                static auto *opExpr = new_static_root<NameExpr>( "?()" );
1082                AlternativeFinder funcOpFinder( indexer, env );
1083                // it's ok if there aren't any defined function ops
1084                funcOpFinder.maybeFind( opExpr );
1085                PRINT(
1086                        std::cerr << "known function ops:" << std::endl;
1087                        printAlts( funcOpFinder.alternatives, std::cerr, 1 );
1088                )
1089
1090                // pre-explode arguments
1091                ExplodedArgs argExpansions;
1092                argExpansions.reserve( argAlternatives.size() );
1093
1094                for ( const AlternativeFinder& arg : argAlternatives ) {
1095                        argExpansions.emplace_back();
1096                        auto& argE = argExpansions.back();
1097                        argE.reserve( arg.alternatives.size() );
1098
1099                        for ( const Alternative& actual : arg ) {
1100                                argE.emplace_back( actual, indexer );
1101                        }
1102                }
1103
1104                AltList candidates;
1105                SemanticErrorException errors;
1106                for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
1107                        try {
1108                                PRINT(
1109                                        std::cerr << "working on alternative: " << std::endl;
1110                                        func->print( std::cerr, 8 );
1111                                )
1112                                // check if the type is pointer to function
1113                                if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
1114                                        if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
1115                                                Alternative newFunc( *func );
1116                                                referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1117                                                makeFunctionAlternatives( newFunc, function, argExpansions,
1118                                                        std::back_inserter( candidates ) );
1119                                        }
1120                                } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
1121                                        EqvClass eqvClass;
1122                                        if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
1123                                                if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
1124                                                        Alternative newFunc( *func );
1125                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1126                                                        makeFunctionAlternatives( newFunc, function, argExpansions,
1127                                                                std::back_inserter( candidates ) );
1128                                                } // if
1129                                        } // if
1130                                }
1131                        } catch ( SemanticErrorException &e ) {
1132                                errors.append( e );
1133                        }
1134                } // for
1135
1136                // try each function operator ?() with each function alternative
1137                if ( ! funcOpFinder.alternatives.empty() ) {
1138                        // add exploded function alternatives to front of argument list
1139                        std::vector<ExplodedActual> funcE;
1140                        funcE.reserve( funcFinder.alternatives.size() );
1141                        for ( const Alternative& actual : funcFinder ) {
1142                                funcE.emplace_back( actual, indexer );
1143                        }
1144                        argExpansions.insert( argExpansions.begin(), move(funcE) );
1145
1146                        for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
1147                                        funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
1148                                try {
1149                                        // check if type is a pointer to function
1150                                        if ( PointerType* pointer = dynamic_cast<PointerType*>(
1151                                                        funcOp->expr->get_result()->stripReferences() ) ) {
1152                                                if ( FunctionType* function =
1153                                                                dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
1154                                                        Alternative newFunc( *funcOp );
1155                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1156                                                        makeFunctionAlternatives( newFunc, function, argExpansions,
1157                                                                std::back_inserter( candidates ) );
1158                                                }
1159                                        }
1160                                } catch ( SemanticErrorException &e ) {
1161                                        errors.append( e );
1162                                }
1163                        }
1164                }
1165
1166                // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
1167                if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
1168
1169                // compute conversionsion costs
1170                for ( Alternative& withFunc : candidates ) {
1171                        Cost cvtCost = computeApplicationConversionCost( withFunc, indexer );
1172
1173                        PRINT(
1174                                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr );
1175                                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
1176                                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
1177                                std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
1178                                std::cerr << "formals are:" << std::endl;
1179                                printAll( function->get_parameters(), std::cerr, 8 );
1180                                std::cerr << "actuals are:" << std::endl;
1181                                printAll( appExpr->get_args(), std::cerr, 8 );
1182                                std::cerr << "bindings are:" << std::endl;
1183                                withFunc.env.print( std::cerr, 8 );
1184                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
1185                        )
1186                        if ( cvtCost != Cost::infinity ) {
1187                                withFunc.cvtCost = cvtCost;
1188                                alternatives.push_back( withFunc );
1189                        } // if
1190                } // for
1191
1192                candidates = move(alternatives);
1193
1194                // use a new list so that alternatives are not examined by addAnonConversions twice.
1195                AltList winners;
1196                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
1197
1198                // function may return struct or union value, in which case we need to add alternatives
1199                // for implicitconversions to each of the anonymous members, must happen after findMinCost
1200                // since anon conversions are never the cheapest expression
1201                for ( const Alternative & alt : winners ) {
1202                        addAnonConversions( alt );
1203                }
1204                spliceBegin( alternatives, winners );
1205
1206                if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
1207                        // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
1208                        // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
1209                        //   forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
1210                        //   const char * x = "hello world";
1211                        //   unsigned char ch = x[0];
1212                        // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
1213                        // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
1214                        // fix this issue in a more robust way.
1215                        targetType = nullptr;
1216                        postvisit( untypedExpr );
1217                }
1218        }
1219
1220        bool isLvalue( Expression *expr ) {
1221                // xxx - recurse into tuples?
1222                return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
1223        }
1224
1225        void AlternativeFinder::Finder::postvisit( AddressExpr *addressExpr ) {
1226                AlternativeFinder finder( indexer, env );
1227                finder.find( addressExpr->get_arg() );
1228                for ( Alternative& alt : finder.alternatives ) {
1229                        if ( isLvalue( alt.expr ) ) {
1230                                alternatives.push_back(
1231                                        Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } );
1232                        } // if
1233                } // for
1234        }
1235
1236        void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
1237                alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
1238        }
1239
1240        Expression * restructureCast( Expression * argExpr, Type * toType, bool isGenerated ) {
1241                if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
1242                        // Argument expression is a tuple and the target type is not void and not a reference type.
1243                        // Cast each member of the tuple to its corresponding target type, producing the tuple of those
1244                        // cast expressions. If there are more components of the tuple than components in the target type,
1245                        // then excess components do not come out in the result expression (but UniqueExprs ensure that
1246                        // side effects will still be done).
1247                        if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
1248                                // expressions which may contain side effects require a single unique instance of the expression.
1249                                argExpr = new UniqueExpr( argExpr );
1250                        }
1251                        std::list< Expression * > componentExprs;
1252                        for ( unsigned int i = 0; i < toType->size(); i++ ) {
1253                                // cast each component
1254                                TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
1255                                componentExprs.push_back( restructureCast( idx, toType->getComponent( i ), isGenerated ) );
1256                        }
1257                        assert( componentExprs.size() > 0 );
1258                        // produce the tuple of casts
1259                        return new TupleExpr( componentExprs );
1260                } else {
1261                        // handle normally
1262                        CastExpr * ret = new CastExpr( argExpr, toType->clone() );
1263                        ret->isGenerated = isGenerated;
1264                        return ret;
1265                }
1266        }
1267
1268        void AlternativeFinder::Finder::postvisit( CastExpr *castExpr ) {
1269                Type *& toType = castExpr->get_result();
1270                assert( toType );
1271                toType = resolveTypeof( toType, indexer );
1272                SymTab::validateType( toType, &indexer );
1273                adjustExprType( toType, env, indexer );
1274
1275                AlternativeFinder finder( indexer, env );
1276                finder.targetType = toType;
1277                finder.findWithAdjustment( castExpr->get_arg() );
1278
1279                AltList candidates;
1280                for ( Alternative & alt : finder.alternatives ) {
1281                        AssertionSet needAssertions, haveAssertions;
1282                        OpenVarSet openVars;
1283
1284                        // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
1285                        // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
1286                        // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
1287                        // to.
1288                        int discardedValues = alt.expr->get_result()->size() - castExpr->get_result()->size();
1289                        if ( discardedValues < 0 ) continue;
1290                        // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1291                        // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1292                        // unification run for side-effects
1293                        unify( castExpr->get_result(), alt.expr->get_result(), alt.env, needAssertions,
1294                                haveAssertions, openVars, indexer );
1295                        Cost thisCost = castCost( alt.expr->get_result(), castExpr->get_result(), indexer,
1296                                alt.env );
1297                        PRINT(
1298                                std::cerr << "working on cast with result: " << castExpr->result << std::endl;
1299                                std::cerr << "and expr type: " << alt.expr->result << std::endl;
1300                                std::cerr << "env: " << alt.env << std::endl;
1301                        )
1302                        if ( thisCost != Cost::infinity ) {
1303                                PRINT(
1304                                        std::cerr << "has finite cost." << std::endl;
1305                                )
1306                                // count one safe conversion for each value that is thrown away
1307                                thisCost.incSafe( discardedValues );
1308                                Alternative newAlt( restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ), alt.env,
1309                                        alt.cost, thisCost );
1310                                inferParameters( needAssertions, haveAssertions, newAlt, openVars,
1311                                        back_inserter( candidates ) );
1312                        } // if
1313                } // for
1314
1315                // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1316                // cvtCost member to the cost member (since the old cost is now irrelevant).  Thus, calling findMinCost twice
1317                // selects first based on argument cost, then on conversion cost.
1318                AltList minArgCost;
1319                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1320                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1321        }
1322
1323        void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
1324                assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
1325                AlternativeFinder finder( indexer, env );
1326                // don't prune here, since it's guaranteed all alternatives will have the same type
1327                finder.findWithoutPrune( castExpr->get_arg() );
1328                for ( Alternative & alt : finder.alternatives ) {
1329                        alternatives.push_back( Alternative(
1330                                new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
1331                                alt.env, alt.cost ) );
1332                }
1333        }
1334
1335        namespace {
1336                /// Gets name from untyped member expression (member must be NameExpr)
1337                const std::string& get_member_name( UntypedMemberExpr *memberExpr ) {
1338                        NameExpr * nameExpr = dynamic_cast< NameExpr * >( memberExpr->get_member() );
1339                        assert( nameExpr );
1340                        return nameExpr->get_name();
1341                }
1342        }
1343
1344        void AlternativeFinder::Finder::postvisit( UntypedMemberExpr *memberExpr ) {
1345                AlternativeFinder funcFinder( indexer, env );
1346                funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
1347                for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
1348                        // 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
1349                        Cost cost = agg->cost;
1350                        Expression * aggrExpr = agg->expr->clone();
1351                        referenceToRvalueConversion( aggrExpr, cost );
1352
1353                        // find member of the given type
1354                        if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
1355                                addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1356                        } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
1357                                addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1358                        } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
1359                                addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() );
1360                        } // if
1361                } // for
1362        }
1363
1364        void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
1365                alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
1366        }
1367
1368        void AlternativeFinder::Finder::postvisit( NameExpr *nameExpr ) {
1369                std::list< SymTab::Indexer::IdData > declList;
1370                indexer.lookupId( nameExpr->name, declList );
1371                PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
1372                for ( auto & data : declList ) {
1373                        Cost cost = Cost::zero;
1374                        Expression * newExpr = data.combine( cost );
1375                        alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
1376                        PRINT(
1377                                std::cerr << "decl is ";
1378                                data.id->print( std::cerr );
1379                                std::cerr << std::endl;
1380                                std::cerr << "newExpr is ";
1381                                newExpr->print( std::cerr );
1382                                std::cerr << std::endl;
1383                        )
1384                        renameTypes( alternatives.back().expr );
1385                        addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
1386                } // for
1387        }
1388
1389        void AlternativeFinder::Finder::postvisit( VariableExpr *variableExpr ) {
1390                // not sufficient to clone here, because variable's type may have changed
1391                // since the VariableExpr was originally created.
1392                alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
1393        }
1394
1395        void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
1396                alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
1397        }
1398
1399        void AlternativeFinder::Finder::postvisit( SizeofExpr *sizeofExpr ) {
1400                if ( sizeofExpr->get_isType() ) {
1401                        Type * newType = sizeofExpr->get_type()->clone();
1402                        alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1403                } else {
1404                        // find all alternatives for the argument to sizeof
1405                        AlternativeFinder finder( indexer, env );
1406                        finder.find( sizeofExpr->get_expr() );
1407                        // find the lowest cost alternative among the alternatives, otherwise ambiguous
1408                        AltList winners;
1409                        findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1410                        if ( winners.size() != 1 ) {
1411                                SemanticError( sizeofExpr->get_expr(), "Ambiguous expression in sizeof operand: " );
1412                        } // if
1413                        // return the lowest cost alternative for the argument
1414                        Alternative &choice = winners.front();
1415                        referenceToRvalueConversion( choice.expr, choice.cost );
1416                        alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1417                } // if
1418        }
1419
1420        void AlternativeFinder::Finder::postvisit( AlignofExpr *alignofExpr ) {
1421                if ( alignofExpr->get_isType() ) {
1422                        Type * newType = alignofExpr->get_type()->clone();
1423                        alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1424                } else {
1425                        // find all alternatives for the argument to sizeof
1426                        AlternativeFinder finder( indexer, env );
1427                        finder.find( alignofExpr->get_expr() );
1428                        // find the lowest cost alternative among the alternatives, otherwise ambiguous
1429                        AltList winners;
1430                        findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1431                        if ( winners.size() != 1 ) {
1432                                SemanticError( alignofExpr->get_expr(), "Ambiguous expression in alignof operand: " );
1433                        } // if
1434                        // return the lowest cost alternative for the argument
1435                        Alternative &choice = winners.front();
1436                        referenceToRvalueConversion( choice.expr, choice.cost );
1437                        alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1438                } // if
1439        }
1440
1441        template< typename StructOrUnionType >
1442        void AlternativeFinder::Finder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
1443                std::list< Declaration* > members;
1444                aggInst->lookup( name, members );
1445                for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1446                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
1447                                alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
1448                                renameTypes( alternatives.back().expr );
1449                        } else {
1450                                assert( false );
1451                        }
1452                }
1453        }
1454
1455        void AlternativeFinder::Finder::postvisit( UntypedOffsetofExpr *offsetofExpr ) {
1456                AlternativeFinder funcFinder( indexer, env );
1457                // xxx - resolveTypeof?
1458                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
1459                        addOffsetof( structInst, offsetofExpr->member );
1460                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
1461                        addOffsetof( unionInst, offsetofExpr->member );
1462                }
1463        }
1464
1465        void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
1466                alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
1467        }
1468
1469        void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
1470                alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
1471        }
1472
1473        namespace {
1474                void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
1475                        // assume no polymorphism
1476                        // assume no implicit conversions
1477                        assert( function->get_parameters().size() == 1 );
1478                        PRINT(
1479                                std::cerr << "resolvAttr: funcDecl is ";
1480                                data.id->print( std::cerr );
1481                                std::cerr << " argType is ";
1482                                argType->print( std::cerr );
1483                                std::cerr << std::endl;
1484                        )
1485                        const SymTab::Indexer & indexer = finder.get_indexer();
1486                        AltList & alternatives = finder.get_alternatives();
1487                        if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1488                                Cost cost = Cost::zero;
1489                                Expression * newExpr = data.combine( cost );
1490                                alternatives.push_back( Alternative( new AttrExpr( newExpr, argType->clone() ), env, Cost::zero, cost ) );
1491                                for ( DeclarationWithType * retVal : function->returnVals ) {
1492                                        alternatives.back().expr->result = retVal->get_type()->clone();
1493                                } // for
1494                        } // if
1495                }
1496        }
1497
1498        void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
1499                // assume no 'pointer-to-attribute'
1500                NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1501                assert( nameExpr );
1502                std::list< SymTab::Indexer::IdData > attrList;
1503                indexer.lookupId( nameExpr->get_name(), attrList );
1504                if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
1505                        for ( auto & data : attrList ) {
1506                                DeclarationWithType * id = data.id;
1507                                // check if the type is function
1508                                if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
1509                                        // assume exactly one parameter
1510                                        if ( function->get_parameters().size() == 1 ) {
1511                                                if ( attrExpr->get_isType() ) {
1512                                                        resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
1513                                                } else {
1514                                                        AlternativeFinder finder( indexer, env );
1515                                                        finder.find( attrExpr->get_expr() );
1516                                                        for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
1517                                                                if ( choice->expr->get_result()->size() == 1 ) {
1518                                                                        resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
1519                                                                } // fi
1520                                                        } // for
1521                                                } // if
1522                                        } // if
1523                                } // if
1524                        } // for
1525                } else {
1526                        for ( auto & data : attrList ) {
1527                                Cost cost = Cost::zero;
1528                                Expression * newExpr = data.combine( cost );
1529                                alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
1530                                renameTypes( alternatives.back().expr );
1531                        } // for
1532                } // if
1533        }
1534
1535        void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
1536                AlternativeFinder firstFinder( indexer, env );
1537                firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
1538                if ( firstFinder.alternatives.empty() ) return;
1539                AlternativeFinder secondFinder( indexer, env );
1540                secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
1541                if ( secondFinder.alternatives.empty() ) return;
1542                for ( const Alternative & first : firstFinder.alternatives ) {
1543                        for ( const Alternative & second : secondFinder.alternatives ) {
1544                                TypeEnvironment compositeEnv;
1545                                compositeEnv.simpleCombine( first.env );
1546                                compositeEnv.simpleCombine( second.env );
1547
1548                                LogicalExpr *newExpr = new LogicalExpr( first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() );
1549                                alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
1550                        }
1551                }
1552        }
1553
1554        void AlternativeFinder::Finder::postvisit( ConditionalExpr *conditionalExpr ) {
1555                // find alternatives for condition
1556                AlternativeFinder firstFinder( indexer, env );
1557                firstFinder.findWithAdjustment( conditionalExpr->arg1 );
1558                if ( firstFinder.alternatives.empty() ) return;
1559                // find alternatives for true expression
1560                AlternativeFinder secondFinder( indexer, env );
1561                secondFinder.findWithAdjustment( conditionalExpr->arg2 );
1562                if ( secondFinder.alternatives.empty() ) return;
1563                // find alterantives for false expression
1564                AlternativeFinder thirdFinder( indexer, env );
1565                thirdFinder.findWithAdjustment( conditionalExpr->arg3 );
1566                if ( thirdFinder.alternatives.empty() ) return;
1567                for ( const Alternative & first : firstFinder.alternatives ) {
1568                        for ( const Alternative & second : secondFinder.alternatives ) {
1569                                for ( const Alternative & third : thirdFinder.alternatives ) {
1570                                        TypeEnvironment compositeEnv;
1571                                        compositeEnv.simpleCombine( first.env );
1572                                        compositeEnv.simpleCombine( second.env );
1573                                        compositeEnv.simpleCombine( third.env );
1574
1575                                        // unify true and false types, then infer parameters to produce new alternatives
1576                                        OpenVarSet openVars;
1577                                        AssertionSet needAssertions, haveAssertions;
1578                                        Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
1579                                        Type* commonType = nullptr;
1580                                        if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1581                                                ConditionalExpr *newExpr = new ConditionalExpr( first.expr->clone(), second.expr->clone(), third.expr->clone() );
1582                                                newExpr->result = commonType ? commonType : second.expr->result->clone();
1583                                                // convert both options to the conditional result type
1584                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
1585                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
1586                                                newAlt.expr = newExpr;
1587                                                inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1588                                        } // if
1589                                } // for
1590                        } // for
1591                } // for
1592        }
1593
1594        void AlternativeFinder::Finder::postvisit( CommaExpr *commaExpr ) {
1595                TypeEnvironment newEnv( env );
1596                Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
1597                AlternativeFinder secondFinder( indexer, newEnv );
1598                secondFinder.findWithAdjustment( commaExpr->get_arg2() );
1599                for ( const Alternative & alt : secondFinder.alternatives ) {
1600                        alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt.expr->clone() ), alt.env, alt.cost ) );
1601                } // for
1602        }
1603
1604        void AlternativeFinder::Finder::postvisit( RangeExpr * rangeExpr ) {
1605                // resolve low and high, accept alternatives whose low and high types unify
1606                AlternativeFinder firstFinder( indexer, env );
1607                firstFinder.findWithAdjustment( rangeExpr->low );
1608                if ( firstFinder.alternatives.empty() ) return;
1609                AlternativeFinder secondFinder( indexer, env );
1610                secondFinder.findWithAdjustment( rangeExpr->high );
1611                if ( secondFinder.alternatives.empty() ) return;
1612                for ( const Alternative & first : firstFinder.alternatives ) {
1613                        for ( const Alternative & second : secondFinder.alternatives ) {
1614                                TypeEnvironment compositeEnv;
1615                                compositeEnv.simpleCombine( first.env );
1616                                compositeEnv.simpleCombine( second.env );
1617                                OpenVarSet openVars;
1618                                AssertionSet needAssertions, haveAssertions;
1619                                Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
1620                                Type* commonType = nullptr;
1621                                if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1622                                        RangeExpr * newExpr = new RangeExpr( first.expr->clone(), second.expr->clone() );
1623                                        newExpr->result = commonType ? commonType : first.expr->result->clone();
1624                                        newAlt.expr = newExpr;
1625                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1626                                } // if
1627                        } // for
1628                } // for
1629        }
1630
1631        void AlternativeFinder::Finder::postvisit( UntypedTupleExpr *tupleExpr ) {
1632                std::vector< AlternativeFinder > subExprAlternatives;
1633                altFinder.findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
1634                        back_inserter( subExprAlternatives ) );
1635                std::vector< AltList > possibilities;
1636                combos( subExprAlternatives.begin(), subExprAlternatives.end(),
1637                        back_inserter( possibilities ) );
1638                for ( const AltList& alts : possibilities ) {
1639                        std::list< Expression * > exprs;
1640                        makeExprList( alts, exprs );
1641
1642                        TypeEnvironment compositeEnv;
1643                        simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
1644                        alternatives.push_back(
1645                                Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
1646                } // for
1647        }
1648
1649        void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
1650                alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1651        }
1652
1653        void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
1654                alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
1655        }
1656
1657        void AlternativeFinder::Finder::postvisit( ConstructorExpr * ctorExpr ) {
1658                AlternativeFinder finder( indexer, env );
1659                // don't prune here, since it's guaranteed all alternatives will have the same type
1660                // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
1661                finder.findWithoutPrune( ctorExpr->get_callExpr() );
1662                for ( Alternative & alt : finder.alternatives ) {
1663                        alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
1664                }
1665        }
1666
1667        void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
1668                alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1669        }
1670
1671        void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
1672                alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
1673        }
1674
1675        void AlternativeFinder::Finder::postvisit( UniqueExpr *unqExpr ) {
1676                AlternativeFinder finder( indexer, env );
1677                finder.findWithAdjustment( unqExpr->get_expr() );
1678                for ( Alternative & alt : finder.alternatives ) {
1679                        // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
1680                        UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
1681                        alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
1682                }
1683        }
1684
1685        void AlternativeFinder::Finder::postvisit( StmtExpr *stmtExpr ) {
1686                StmtExpr * newStmtExpr = stmtExpr->clone();
1687                ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
1688                // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
1689                alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
1690        }
1691
1692        void AlternativeFinder::Finder::postvisit( UntypedInitExpr *initExpr ) {
1693                // handle each option like a cast
1694                AltList candidates;
1695                PRINT(
1696                        std::cerr << "untyped init expr: " << initExpr << std::endl;
1697                )
1698                // O(N^2) checks of d-types with e-types
1699                for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
1700                        Type * toType = resolveTypeof( initAlt.type->clone(), indexer );
1701                        SymTab::validateType( toType, &indexer );
1702                        adjustExprType( toType, env, indexer );
1703                        // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
1704                        // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
1705                        // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
1706                        AlternativeFinder finder( indexer, env );
1707                        finder.targetType = toType;
1708                        finder.findWithAdjustment( initExpr->get_expr() );
1709                        for ( Alternative & alt : finder.get_alternatives() ) {
1710                                TypeEnvironment newEnv( alt.env );
1711                                AssertionSet needAssertions, haveAssertions;
1712                                OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
1713                                PRINT(
1714                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
1715                                 )
1716                                // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
1717                                // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
1718                                // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
1719                                // to.
1720                                int discardedValues = alt.expr->get_result()->size() - toType->size();
1721                                if ( discardedValues < 0 ) continue;
1722                                // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1723                                // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1724                                // unification run for side-effects
1725                                unify( toType, alt.expr->get_result(), newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
1726
1727                                Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );
1728                                if ( thisCost != Cost::infinity ) {
1729                                        // count one safe conversion for each value that is thrown away
1730                                        thisCost.incSafe( discardedValues );
1731                                        Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
1732                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
1733                                }
1734                        }
1735                }
1736
1737                // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1738                // cvtCost member to the cost member (since the old cost is now irrelevant).  Thus, calling findMinCost twice
1739                // selects first based on argument cost, then on conversion cost.
1740                AltList minArgCost;
1741                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1742                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1743        }
1744
1745        void AlternativeFinder::Finder::postvisit( InitExpr * ) {
1746                assertf( false, "AlternativeFinder should never see a resolved InitExpr." );
1747        }
1748
1749        void AlternativeFinder::Finder::postvisit( DeletedExpr * ) {
1750                assertf( false, "AlternativeFinder should never see a DeletedExpr." );
1751        }
1752} // namespace ResolvExpr
1753
1754// Local Variables: //
1755// tab-width: 4 //
1756// mode: c++ //
1757// compile-command: "make install" //
1758// End: //
Note: See TracBrowser for help on using the repository browser.