source: src/ResolvExpr/AlternativeFinder.cc @ eba74ba

new-envwith_gc
Last change on this file since eba74ba was eba74ba, 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                                // ^^^ need to handle the case where a tuple has a default argument
697                                if ( ! instantiateArgument(
698                                                type, nullptr, args, results, genStart, indexer, nTuples ) )
699                                        return false;
700                                nTuples = 0;
701                        }
702                        // re-consititute tuples for final generation
703                        for ( auto i = genStart; i < results.size(); ++i ) {
704                                results[i].endTuple( results );
705                        }
706                        return true;
707                } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
708                        // formalType is a ttype, consumes all remaining arguments
709                        // xxx - mixing default arguments with variadic??
710
711                        // completed tuples; will be spliced to end of results to finish
712                        std::vector<ArgPack> finalResults{};
713
714                        // iterate until all results completed
715                        std::size_t genEnd;
716                        ++nTuples;
717                        do {
718                                genEnd = results.size();
719
720                                // add another argument to results
721                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
722                                        auto nextArg = results[i].nextArg;
723
724                                        // use next element of exploded tuple if present
725                                        if ( results[i].hasExpl() ) {
726                                                const ExplodedActual& expl = results[i].getExpl( args );
727
728                                                unsigned nextExpl = results[i].nextExpl + 1;
729                                                if ( nextExpl == expl.exprs.size() ) {
730                                                        nextExpl = 0;
731                                                }
732
733                                                results.emplace_back(
734                                                        i, expl.exprs[results[i].nextExpl], copy(results[i].env),
735                                                        copy(results[i].need), copy(results[i].have),
736                                                        copy(results[i].openVars), nextArg, nTuples, Cost::zero, nextExpl,
737                                                        results[i].explAlt );
738
739                                                continue;
740                                        }
741
742                                        // finish result when out of arguments
743                                        if ( nextArg >= args.size() ) {
744                                                ArgPack newResult{
745                                                        results[i].env, results[i].need, results[i].have,
746                                                        results[i].openVars };
747                                                newResult.nextArg = nextArg;
748                                                Type* argType;
749
750                                                if ( nTuples > 0 || ! results[i].expr ) {
751                                                        // first iteration or no expression to clone,
752                                                        // push empty tuple expression
753                                                        newResult.parent = i;
754                                                        std::list<Expression*> emptyList;
755                                                        newResult.expr = new TupleExpr{ emptyList };
756                                                        argType = newResult.expr->get_result();
757                                                } else {
758                                                        // clone result to collect tuple
759                                                        newResult.parent = results[i].parent;
760                                                        newResult.cost = results[i].cost;
761                                                        newResult.tupleStart = results[i].tupleStart;
762                                                        newResult.expr = results[i].expr->clone();
763                                                        argType = newResult.expr->get_result();
764
765                                                        if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
766                                                                // the case where a ttype value is passed directly is special,
767                                                                // e.g. for argument forwarding purposes
768                                                                // xxx - what if passing multiple arguments, last of which is
769                                                                //       ttype?
770                                                                // xxx - what would happen if unify was changed so that unifying
771                                                                //       tuple
772                                                                // types flattened both before unifying lists? then pass in
773                                                                // TupleType (ttype) below.
774                                                                --newResult.tupleStart;
775                                                        } else {
776                                                                // collapse leftover arguments into tuple
777                                                                newResult.endTuple( results );
778                                                                argType = newResult.expr->get_result();
779                                                        }
780                                                }
781
782                                                // check unification for ttype before adding to final
783                                                if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have,
784                                                                newResult.openVars, indexer ) ) {
785                                                        finalResults.push_back( move(newResult) );
786                                                }
787
788                                                continue;
789                                        }
790
791                                        // add each possible next argument
792                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
793                                                const ExplodedActual& expl = args[nextArg][j];
794
795                                                // fresh copies of parent parameters for this iteration
796                                                TypeEnvironment env = results[i].env;
797                                                OpenVarSet openVars = results[i].openVars;
798
799                                                env.addActual( expl.env, openVars );
800
801                                                // skip empty tuple arguments by (near-)cloning parent into next gen
802                                                if ( expl.exprs.empty() ) {
803                                                        results.emplace_back(
804                                                                results[i], move(env), copy(results[i].need),
805                                                                copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
806
807                                                        continue;
808                                                }
809
810                                                // add new result
811                                                results.emplace_back(
812                                                        i, expl.exprs.front(), move(env), copy(results[i].need),
813                                                        copy(results[i].have), move(openVars), nextArg + 1,
814                                                        nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
815                                        }
816                                }
817
818                                // reset for next round
819                                genStart = genEnd;
820                                nTuples = 0;
821                        } while ( genEnd != results.size() );
822
823                        // splice final results onto results
824                        for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
825                                results.push_back( move(finalResults[i]) );
826                        }
827                        return ! finalResults.empty();
828                }
829
830                // iterate each current subresult
831                std::size_t genEnd = results.size();
832                for ( std::size_t i = genStart; i < genEnd; ++i ) {
833                        auto nextArg = results[i].nextArg;
834
835                        // use remainder of exploded tuple if present
836                        if ( results[i].hasExpl() ) {
837                                const ExplodedActual& expl = results[i].getExpl( args );
838                                Expression* expr = expl.exprs[results[i].nextExpl];
839
840                                TypeEnvironment env = results[i].env;
841                                AssertionSet need = results[i].need, have = results[i].have;
842                                OpenVarSet openVars = results[i].openVars;
843
844                                Type* actualType = expr->get_result();
845
846                                PRINT(
847                                        std::cerr << "formal type is ";
848                                        formalType->print( std::cerr );
849                                        std::cerr << std::endl << "actual type is ";
850                                        actualType->print( std::cerr );
851                                        std::cerr << std::endl;
852                                )
853
854                                if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
855                                        unsigned nextExpl = results[i].nextExpl + 1;
856                                        if ( nextExpl == expl.exprs.size() ) {
857                                                nextExpl = 0;
858                                        }
859
860                                        results.emplace_back(
861                                                i, expr, move(env), move(need), move(have), move(openVars), nextArg,
862                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
863                                }
864
865                                continue;
866                        }
867
868                        // use default initializers if out of arguments
869                        if ( nextArg >= args.size() ) {
870                                if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
871                                        if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
872                                                TypeEnvironment env = results[i].env;
873                                                AssertionSet need = results[i].need, have = results[i].have;
874                                                OpenVarSet openVars = results[i].openVars;
875
876                                                if ( unify( formalType, cnst->get_type(), env, need, have, openVars,
877                                                                indexer ) ) {
878                                                        results.emplace_back(
879                                                                i, cnstExpr, move(env), move(need), move(have),
880                                                                move(openVars), nextArg, nTuples );
881                                                }
882                                        }
883                                }
884
885                                continue;
886                        }
887
888                        // Check each possible next argument
889                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
890                                const ExplodedActual& expl = args[nextArg][j];
891
892                                // fresh copies of parent parameters for this iteration
893                                TypeEnvironment env = results[i].env;
894                                AssertionSet need = results[i].need, have = results[i].have;
895                                OpenVarSet openVars = results[i].openVars;
896
897                                env.addActual( expl.env, openVars );
898
899                                // skip empty tuple arguments by (near-)cloning parent into next gen
900                                if ( expl.exprs.empty() ) {
901                                        results.emplace_back(
902                                                results[i], move(env), move(need), move(have), move(openVars),
903                                                nextArg + 1, expl.cost );
904
905                                        continue;
906                                }
907
908                                // consider only first exploded actual
909                                Expression* expr = expl.exprs.front();
910                                Type* actualType = expr->result->clone();
911
912                                PRINT(
913                                        std::cerr << "formal type is ";
914                                        formalType->print( std::cerr );
915                                        std::cerr << std::endl << "actual type is ";
916                                        actualType->print( std::cerr );
917                                        std::cerr << std::endl;
918                                )
919
920                                // attempt to unify types
921                                if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
922                                        // add new result
923                                        results.emplace_back(
924                                                i, expr, move(env), move(need), move(have), move(openVars), nextArg + 1,
925                                                nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
926                                }
927                        }
928                }
929
930                // reset for next parameter
931                genStart = genEnd;
932
933                return genEnd != results.size();
934        }
935
936        template<typename OutputIterator>
937        void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func, ArgPack& result,
938                        const std::vector<ArgPack>& results, OutputIterator out ) {
939                ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
940                // sum cost and accumulate actuals
941                std::list<Expression*>& args = appExpr->args;
942                Cost cost = func.cost;
943                const ArgPack* pack = &result;
944                while ( pack->expr ) {
945                        args.push_front( pack->expr->clone() );
946                        cost += pack->cost;
947                        pack = &results[pack->parent];
948                }
949                // build and validate new alternative
950                Alternative newAlt( appExpr, result.env, cost );
951                PRINT(
952                        std::cerr << "instantiate function success: " << appExpr << std::endl;
953                        std::cerr << "need assertions:" << std::endl;
954                        printAssertionSet( result.need, std::cerr, 8 );
955                )
956                inferParameters( result.need, result.have, newAlt, result.openVars, out );
957        }
958
959        template<typename OutputIterator>
960        void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
961                        FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
962                OpenVarSet funcOpenVars;
963                AssertionSet funcNeed, funcHave;
964                TypeEnvironment funcEnv( func.env );
965                makeUnifiableVars( funcType, funcOpenVars, funcNeed );
966                // add all type variables as open variables now so that those not used in the parameter
967                // list are still considered open.
968                funcEnv.add( funcType->forall );
969
970                if ( targetType && ! targetType->isVoid() && ! funcType->returnVals.empty() ) {
971                        // attempt to narrow based on expected target type
972                        Type * returnType = funcType->returnVals.front()->get_type();
973                        if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
974                                        indexer ) ) {
975                                // unification failed, don't pursue this function alternative
976                                return;
977                        }
978                }
979
980                // iteratively build matches, one parameter at a time
981                std::vector<ArgPack> results;
982                results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } );
983                std::size_t genStart = 0;
984
985                for ( DeclarationWithType* formal : funcType->parameters ) {
986                        ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
987                        if ( ! instantiateArgument(
988                                        obj->type, obj->init, args, results, genStart, indexer ) )
989                                return;
990                }
991
992                if ( funcType->get_isVarArgs() ) {
993                        // append any unused arguments to vararg pack
994                        std::size_t genEnd;
995                        do {
996                                genEnd = results.size();
997
998                                // iterate results
999                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
1000                                        auto nextArg = results[i].nextArg;
1001
1002                                        // use remainder of exploded tuple if present
1003                                        if ( results[i].hasExpl() ) {
1004                                                const ExplodedActual& expl = results[i].getExpl( args );
1005
1006                                                unsigned nextExpl = results[i].nextExpl + 1;
1007                                                if ( nextExpl == expl.exprs.size() ) {
1008                                                        nextExpl = 0;
1009                                                }
1010
1011                                                results.emplace_back(
1012                                                        i, expl.exprs[results[i].nextExpl], copy(results[i].env),
1013                                                        copy(results[i].need), copy(results[i].have),
1014                                                        copy(results[i].openVars), nextArg, 0, Cost::zero, nextExpl,
1015                                                        results[i].explAlt );
1016
1017                                                continue;
1018                                        }
1019
1020                                        // finish result when out of arguments
1021                                        if ( nextArg >= args.size() ) {
1022                                                validateFunctionAlternative( func, results[i], results, out );
1023
1024                                                continue;
1025                                        }
1026
1027                                        // add each possible next argument
1028                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1029                                                const ExplodedActual& expl = args[nextArg][j];
1030
1031                                                // fresh copies of parent parameters for this iteration
1032                                                TypeEnvironment env = results[i].env;
1033                                                OpenVarSet openVars = results[i].openVars;
1034
1035                                                env.addActual( expl.env, openVars );
1036
1037                                                // skip empty tuple arguments by (near-)cloning parent into next gen
1038                                                if ( expl.exprs.empty() ) {
1039                                                        results.emplace_back(
1040                                                                results[i], move(env), copy(results[i].need),
1041                                                                copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
1042
1043                                                        continue;
1044                                                }
1045
1046                                                // add new result
1047                                                results.emplace_back(
1048                                                        i, expl.exprs.front(), move(env), copy(results[i].need),
1049                                                        copy(results[i].have), move(openVars), nextArg + 1, 0,
1050                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
1051                                        }
1052                                }
1053
1054                                genStart = genEnd;
1055                        } while ( genEnd != results.size() );
1056                } else {
1057                        // filter out results that don't use all the arguments
1058                        for ( std::size_t i = genStart; i < results.size(); ++i ) {
1059                                ArgPack& result = results[i];
1060                                if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
1061                                        validateFunctionAlternative( func, result, results, out );
1062                                }
1063                        }
1064                }
1065        }
1066
1067        void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
1068                AlternativeFinder funcFinder( indexer, env );
1069                funcFinder.findWithAdjustment( untypedExpr->function );
1070                // if there are no function alternatives, then proceeding is a waste of time.
1071                if ( funcFinder.alternatives.empty() ) return;
1072
1073                std::vector< AlternativeFinder > argAlternatives;
1074                altFinder.findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
1075                        back_inserter( argAlternatives ) );
1076
1077                // take care of possible tuple assignments
1078                // if not tuple assignment, assignment is taken care of as a normal function call
1079                Tuples::handleTupleAssignment( altFinder, untypedExpr, argAlternatives );
1080
1081                // find function operators
1082                static auto *opExpr = new_static_root<NameExpr>( "?()" );
1083                AlternativeFinder funcOpFinder( indexer, env );
1084                // it's ok if there aren't any defined function ops
1085                funcOpFinder.maybeFind( opExpr );
1086                PRINT(
1087                        std::cerr << "known function ops:" << std::endl;
1088                        printAlts( funcOpFinder.alternatives, std::cerr, 1 );
1089                )
1090
1091                // pre-explode arguments
1092                ExplodedArgs argExpansions;
1093                argExpansions.reserve( argAlternatives.size() );
1094
1095                for ( const AlternativeFinder& arg : argAlternatives ) {
1096                        argExpansions.emplace_back();
1097                        auto& argE = argExpansions.back();
1098                        argE.reserve( arg.alternatives.size() );
1099
1100                        for ( const Alternative& actual : arg ) {
1101                                argE.emplace_back( actual, indexer );
1102                        }
1103                }
1104
1105                AltList candidates;
1106                SemanticErrorException errors;
1107                for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
1108                        try {
1109                                PRINT(
1110                                        std::cerr << "working on alternative: " << std::endl;
1111                                        func->print( std::cerr, 8 );
1112                                )
1113                                // check if the type is pointer to function
1114                                if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
1115                                        if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
1116                                                Alternative newFunc( *func );
1117                                                referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1118                                                makeFunctionAlternatives( newFunc, function, argExpansions,
1119                                                        std::back_inserter( candidates ) );
1120                                        }
1121                                } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
1122                                        EqvClass eqvClass;
1123                                        if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
1124                                                if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
1125                                                        Alternative newFunc( *func );
1126                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1127                                                        makeFunctionAlternatives( newFunc, function, argExpansions,
1128                                                                std::back_inserter( candidates ) );
1129                                                } // if
1130                                        } // if
1131                                }
1132                        } catch ( SemanticErrorException &e ) {
1133                                errors.append( e );
1134                        }
1135                } // for
1136
1137                // try each function operator ?() with each function alternative
1138                if ( ! funcOpFinder.alternatives.empty() ) {
1139                        // add exploded function alternatives to front of argument list
1140                        std::vector<ExplodedActual> funcE;
1141                        funcE.reserve( funcFinder.alternatives.size() );
1142                        for ( const Alternative& actual : funcFinder ) {
1143                                funcE.emplace_back( actual, indexer );
1144                        }
1145                        argExpansions.insert( argExpansions.begin(), move(funcE) );
1146
1147                        for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
1148                                        funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
1149                                try {
1150                                        // check if type is a pointer to function
1151                                        if ( PointerType* pointer = dynamic_cast<PointerType*>(
1152                                                        funcOp->expr->get_result()->stripReferences() ) ) {
1153                                                if ( FunctionType* function =
1154                                                                dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
1155                                                        Alternative newFunc( *funcOp );
1156                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
1157                                                        makeFunctionAlternatives( newFunc, function, argExpansions,
1158                                                                std::back_inserter( candidates ) );
1159                                                }
1160                                        }
1161                                } catch ( SemanticErrorException &e ) {
1162                                        errors.append( e );
1163                                }
1164                        }
1165                }
1166
1167                // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
1168                if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
1169
1170                // compute conversionsion costs
1171                for ( Alternative& withFunc : candidates ) {
1172                        Cost cvtCost = computeApplicationConversionCost( withFunc, indexer );
1173
1174                        PRINT(
1175                                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr );
1176                                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
1177                                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
1178                                std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
1179                                std::cerr << "formals are:" << std::endl;
1180                                printAll( function->get_parameters(), std::cerr, 8 );
1181                                std::cerr << "actuals are:" << std::endl;
1182                                printAll( appExpr->get_args(), std::cerr, 8 );
1183                                std::cerr << "bindings are:" << std::endl;
1184                                withFunc.env.print( std::cerr, 8 );
1185                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
1186                        )
1187                        if ( cvtCost != Cost::infinity ) {
1188                                withFunc.cvtCost = cvtCost;
1189                                alternatives.push_back( withFunc );
1190                        } // if
1191                } // for
1192
1193                candidates = move(alternatives);
1194
1195                // use a new list so that alternatives are not examined by addAnonConversions twice.
1196                AltList winners;
1197                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
1198
1199                // function may return struct or union value, in which case we need to add alternatives
1200                // for implicitconversions to each of the anonymous members, must happen after findMinCost
1201                // since anon conversions are never the cheapest expression
1202                for ( const Alternative & alt : winners ) {
1203                        addAnonConversions( alt );
1204                }
1205                spliceBegin( alternatives, winners );
1206
1207                if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
1208                        // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
1209                        // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
1210                        //   forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
1211                        //   const char * x = "hello world";
1212                        //   unsigned char ch = x[0];
1213                        // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
1214                        // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
1215                        // fix this issue in a more robust way.
1216                        targetType = nullptr;
1217                        postvisit( untypedExpr );
1218                }
1219        }
1220
1221        bool isLvalue( Expression *expr ) {
1222                // xxx - recurse into tuples?
1223                return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
1224        }
1225
1226        void AlternativeFinder::Finder::postvisit( AddressExpr *addressExpr ) {
1227                AlternativeFinder finder( indexer, env );
1228                finder.find( addressExpr->get_arg() );
1229                for ( Alternative& alt : finder.alternatives ) {
1230                        if ( isLvalue( alt.expr ) ) {
1231                                alternatives.push_back(
1232                                        Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } );
1233                        } // if
1234                } // for
1235        }
1236
1237        void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
1238                alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
1239        }
1240
1241        Expression * restructureCast( Expression * argExpr, Type * toType, bool isGenerated ) {
1242                if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
1243                        // Argument expression is a tuple and the target type is not void and not a reference type.
1244                        // Cast each member of the tuple to its corresponding target type, producing the tuple of those
1245                        // cast expressions. If there are more components of the tuple than components in the target type,
1246                        // then excess components do not come out in the result expression (but UniqueExprs ensure that
1247                        // side effects will still be done).
1248                        if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
1249                                // expressions which may contain side effects require a single unique instance of the expression.
1250                                argExpr = new UniqueExpr( argExpr );
1251                        }
1252                        std::list< Expression * > componentExprs;
1253                        for ( unsigned int i = 0; i < toType->size(); i++ ) {
1254                                // cast each component
1255                                TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
1256                                componentExprs.push_back( restructureCast( idx, toType->getComponent( i ), isGenerated ) );
1257                        }
1258                        assert( componentExprs.size() > 0 );
1259                        // produce the tuple of casts
1260                        return new TupleExpr( componentExprs );
1261                } else {
1262                        // handle normally
1263                        CastExpr * ret = new CastExpr( argExpr, toType->clone() );
1264                        ret->isGenerated = isGenerated;
1265                        return ret;
1266                }
1267        }
1268
1269        void AlternativeFinder::Finder::postvisit( CastExpr *castExpr ) {
1270                Type *& toType = castExpr->get_result();
1271                assert( toType );
1272                toType = resolveTypeof( toType, indexer );
1273                SymTab::validateType( toType, &indexer );
1274                adjustExprType( toType, env, indexer );
1275
1276                AlternativeFinder finder( indexer, env );
1277                finder.targetType = toType;
1278                finder.findWithAdjustment( castExpr->arg );
1279
1280                AltList candidates;
1281                for ( Alternative & alt : finder.alternatives ) {
1282                        AssertionSet needAssertions, haveAssertions;
1283                        OpenVarSet openVars;
1284
1285                        alt.env.extractOpenVars( openVars );
1286
1287                        // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
1288                        // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
1289                        // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
1290                        // to.
1291                        int discardedValues = alt.expr->result->size() - castExpr->result->size();
1292                        if ( discardedValues < 0 ) continue;
1293                        // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1294                        // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1295                        // unification run for side-effects
1296                        unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
1297                                haveAssertions, openVars, indexer );
1298                        Cost thisCost = castCost( alt.expr->result, castExpr->result, indexer,
1299                                alt.env );
1300                        PRINT(
1301                                std::cerr << "working on cast with result: " << castExpr->result << std::endl;
1302                                std::cerr << "and expr type: " << alt.expr->result << std::endl;
1303                                std::cerr << "env: " << alt.env << std::endl;
1304                        )
1305                        if ( thisCost != Cost::infinity ) {
1306                                PRINT(
1307                                        std::cerr << "has finite cost." << std::endl;
1308                                )
1309                                // count one safe conversion for each value that is thrown away
1310                                thisCost.incSafe( discardedValues );
1311                                Alternative newAlt( restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ), alt.env,
1312                                        alt.cost, thisCost );
1313                                inferParameters( needAssertions, haveAssertions, newAlt, openVars,
1314                                        back_inserter( candidates ) );
1315                        } // if
1316                } // for
1317
1318                // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1319                // cvtCost member to the cost member (since the old cost is now irrelevant).  Thus, calling findMinCost twice
1320                // selects first based on argument cost, then on conversion cost.
1321                AltList minArgCost;
1322                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1323                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1324        }
1325
1326        void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
1327                assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
1328                AlternativeFinder finder( indexer, env );
1329                // don't prune here, since it's guaranteed all alternatives will have the same type
1330                finder.findWithoutPrune( castExpr->get_arg() );
1331                for ( Alternative & alt : finder.alternatives ) {
1332                        alternatives.push_back( Alternative(
1333                                new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
1334                                alt.env, alt.cost ) );
1335                }
1336        }
1337
1338        namespace {
1339                /// Gets name from untyped member expression (member must be NameExpr)
1340                const std::string& get_member_name( UntypedMemberExpr *memberExpr ) {
1341                        NameExpr * nameExpr = dynamic_cast< NameExpr * >( memberExpr->get_member() );
1342                        assert( nameExpr );
1343                        return nameExpr->get_name();
1344                }
1345        }
1346
1347        void AlternativeFinder::Finder::postvisit( UntypedMemberExpr *memberExpr ) {
1348                AlternativeFinder funcFinder( indexer, env );
1349                funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
1350                for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
1351                        // 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
1352                        Cost cost = agg->cost;
1353                        Expression * aggrExpr = agg->expr->clone();
1354                        referenceToRvalueConversion( aggrExpr, cost );
1355
1356                        // find member of the given type
1357                        if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
1358                                addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1359                        } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
1360                                addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
1361                        } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
1362                                addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() );
1363                        } // if
1364                } // for
1365        }
1366
1367        void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
1368                alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
1369        }
1370
1371        void AlternativeFinder::Finder::postvisit( NameExpr *nameExpr ) {
1372                std::list< SymTab::Indexer::IdData > declList;
1373                indexer.lookupId( nameExpr->name, declList );
1374                PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
1375                for ( auto & data : declList ) {
1376                        Cost cost = Cost::zero;
1377                        Expression * newExpr = data.combine( cost );
1378                        alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
1379                        PRINT(
1380                                std::cerr << "decl is ";
1381                                data.id->print( std::cerr );
1382                                std::cerr << std::endl;
1383                                std::cerr << "newExpr is ";
1384                                newExpr->print( std::cerr );
1385                                std::cerr << std::endl;
1386                        )
1387                        renameTypes( alternatives.back().expr );
1388                        addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
1389                } // for
1390        }
1391
1392        void AlternativeFinder::Finder::postvisit( VariableExpr *variableExpr ) {
1393                // not sufficient to clone here, because variable's type may have changed
1394                // since the VariableExpr was originally created.
1395                alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
1396        }
1397
1398        void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
1399                alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
1400        }
1401
1402        void AlternativeFinder::Finder::postvisit( SizeofExpr *sizeofExpr ) {
1403                if ( sizeofExpr->get_isType() ) {
1404                        Type * newType = sizeofExpr->get_type()->clone();
1405                        alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1406                } else {
1407                        // find all alternatives for the argument to sizeof
1408                        AlternativeFinder finder( indexer, env );
1409                        finder.find( sizeofExpr->get_expr() );
1410                        // find the lowest cost alternative among the alternatives, otherwise ambiguous
1411                        AltList winners;
1412                        findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1413                        if ( winners.size() != 1 ) {
1414                                SemanticError( sizeofExpr->get_expr(), "Ambiguous expression in sizeof operand: " );
1415                        } // if
1416                        // return the lowest cost alternative for the argument
1417                        Alternative &choice = winners.front();
1418                        referenceToRvalueConversion( choice.expr, choice.cost );
1419                        alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1420                } // if
1421        }
1422
1423        void AlternativeFinder::Finder::postvisit( AlignofExpr *alignofExpr ) {
1424                if ( alignofExpr->get_isType() ) {
1425                        Type * newType = alignofExpr->get_type()->clone();
1426                        alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1427                } else {
1428                        // find all alternatives for the argument to sizeof
1429                        AlternativeFinder finder( indexer, env );
1430                        finder.find( alignofExpr->get_expr() );
1431                        // find the lowest cost alternative among the alternatives, otherwise ambiguous
1432                        AltList winners;
1433                        findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1434                        if ( winners.size() != 1 ) {
1435                                SemanticError( alignofExpr->get_expr(), "Ambiguous expression in alignof operand: " );
1436                        } // if
1437                        // return the lowest cost alternative for the argument
1438                        Alternative &choice = winners.front();
1439                        referenceToRvalueConversion( choice.expr, choice.cost );
1440                        alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1441                } // if
1442        }
1443
1444        template< typename StructOrUnionType >
1445        void AlternativeFinder::Finder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
1446                std::list< Declaration* > members;
1447                aggInst->lookup( name, members );
1448                for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1449                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
1450                                alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
1451                                renameTypes( alternatives.back().expr );
1452                        } else {
1453                                assert( false );
1454                        }
1455                }
1456        }
1457
1458        void AlternativeFinder::Finder::postvisit( UntypedOffsetofExpr *offsetofExpr ) {
1459                AlternativeFinder funcFinder( indexer, env );
1460                // xxx - resolveTypeof?
1461                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
1462                        addOffsetof( structInst, offsetofExpr->member );
1463                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
1464                        addOffsetof( unionInst, offsetofExpr->member );
1465                }
1466        }
1467
1468        void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
1469                alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
1470        }
1471
1472        void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
1473                alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
1474        }
1475
1476        namespace {
1477                void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
1478                        // assume no polymorphism
1479                        // assume no implicit conversions
1480                        assert( function->get_parameters().size() == 1 );
1481                        PRINT(
1482                                std::cerr << "resolvAttr: funcDecl is ";
1483                                data.id->print( std::cerr );
1484                                std::cerr << " argType is ";
1485                                argType->print( std::cerr );
1486                                std::cerr << std::endl;
1487                        )
1488                        const SymTab::Indexer & indexer = finder.get_indexer();
1489                        AltList & alternatives = finder.get_alternatives();
1490                        if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1491                                Cost cost = Cost::zero;
1492                                Expression * newExpr = data.combine( cost );
1493                                alternatives.push_back( Alternative( new AttrExpr( newExpr, argType->clone() ), env, Cost::zero, cost ) );
1494                                for ( DeclarationWithType * retVal : function->returnVals ) {
1495                                        alternatives.back().expr->result = retVal->get_type()->clone();
1496                                } // for
1497                        } // if
1498                }
1499        }
1500
1501        void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
1502                // assume no 'pointer-to-attribute'
1503                NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1504                assert( nameExpr );
1505                std::list< SymTab::Indexer::IdData > attrList;
1506                indexer.lookupId( nameExpr->get_name(), attrList );
1507                if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
1508                        for ( auto & data : attrList ) {
1509                                DeclarationWithType * id = data.id;
1510                                // check if the type is function
1511                                if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
1512                                        // assume exactly one parameter
1513                                        if ( function->get_parameters().size() == 1 ) {
1514                                                if ( attrExpr->get_isType() ) {
1515                                                        resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
1516                                                } else {
1517                                                        AlternativeFinder finder( indexer, env );
1518                                                        finder.find( attrExpr->get_expr() );
1519                                                        for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
1520                                                                if ( choice->expr->get_result()->size() == 1 ) {
1521                                                                        resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
1522                                                                } // fi
1523                                                        } // for
1524                                                } // if
1525                                        } // if
1526                                } // if
1527                        } // for
1528                } else {
1529                        for ( auto & data : attrList ) {
1530                                Cost cost = Cost::zero;
1531                                Expression * newExpr = data.combine( cost );
1532                                alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
1533                                renameTypes( alternatives.back().expr );
1534                        } // for
1535                } // if
1536        }
1537
1538        void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
1539                AlternativeFinder firstFinder( indexer, env );
1540                firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
1541                if ( firstFinder.alternatives.empty() ) return;
1542                AlternativeFinder secondFinder( indexer, env );
1543                secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
1544                if ( secondFinder.alternatives.empty() ) return;
1545                for ( const Alternative & first : firstFinder.alternatives ) {
1546                        for ( const Alternative & second : secondFinder.alternatives ) {
1547                                TypeEnvironment compositeEnv;
1548                                compositeEnv.simpleCombine( first.env );
1549                                compositeEnv.simpleCombine( second.env );
1550
1551                                LogicalExpr *newExpr = new LogicalExpr( first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() );
1552                                alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
1553                        }
1554                }
1555        }
1556
1557        void AlternativeFinder::Finder::postvisit( ConditionalExpr *conditionalExpr ) {
1558                // find alternatives for condition
1559                AlternativeFinder firstFinder( indexer, env );
1560                firstFinder.findWithAdjustment( conditionalExpr->arg1 );
1561                if ( firstFinder.alternatives.empty() ) return;
1562                // find alternatives for true expression
1563                AlternativeFinder secondFinder( indexer, env );
1564                secondFinder.findWithAdjustment( conditionalExpr->arg2 );
1565                if ( secondFinder.alternatives.empty() ) return;
1566                // find alterantives for false expression
1567                AlternativeFinder thirdFinder( indexer, env );
1568                thirdFinder.findWithAdjustment( conditionalExpr->arg3 );
1569                if ( thirdFinder.alternatives.empty() ) return;
1570                for ( const Alternative & first : firstFinder.alternatives ) {
1571                        for ( const Alternative & second : secondFinder.alternatives ) {
1572                                for ( const Alternative & third : thirdFinder.alternatives ) {
1573                                        TypeEnvironment compositeEnv;
1574                                        compositeEnv.simpleCombine( first.env );
1575                                        compositeEnv.simpleCombine( second.env );
1576                                        compositeEnv.simpleCombine( third.env );
1577
1578                                        // unify true and false types, then infer parameters to produce new alternatives
1579                                        OpenVarSet openVars;
1580                                        AssertionSet needAssertions, haveAssertions;
1581                                        Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
1582                                        Type* commonType = nullptr;
1583                                        if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1584                                                ConditionalExpr *newExpr = new ConditionalExpr( first.expr->clone(), second.expr->clone(), third.expr->clone() );
1585                                                newExpr->result = commonType ? commonType : second.expr->result->clone();
1586                                                // convert both options to the conditional result type
1587                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
1588                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
1589                                                newAlt.expr = newExpr;
1590                                                inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1591                                        } // if
1592                                } // for
1593                        } // for
1594                } // for
1595        }
1596
1597        void AlternativeFinder::Finder::postvisit( CommaExpr *commaExpr ) {
1598                TypeEnvironment newEnv( env );
1599                Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
1600                AlternativeFinder secondFinder( indexer, newEnv );
1601                secondFinder.findWithAdjustment( commaExpr->get_arg2() );
1602                for ( const Alternative & alt : secondFinder.alternatives ) {
1603                        alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt.expr->clone() ), alt.env, alt.cost ) );
1604                } // for
1605        }
1606
1607        void AlternativeFinder::Finder::postvisit( RangeExpr * rangeExpr ) {
1608                // resolve low and high, accept alternatives whose low and high types unify
1609                AlternativeFinder firstFinder( indexer, env );
1610                firstFinder.findWithAdjustment( rangeExpr->low );
1611                if ( firstFinder.alternatives.empty() ) return;
1612                AlternativeFinder secondFinder( indexer, env );
1613                secondFinder.findWithAdjustment( rangeExpr->high );
1614                if ( secondFinder.alternatives.empty() ) return;
1615                for ( const Alternative & first : firstFinder.alternatives ) {
1616                        for ( const Alternative & second : secondFinder.alternatives ) {
1617                                TypeEnvironment compositeEnv;
1618                                compositeEnv.simpleCombine( first.env );
1619                                compositeEnv.simpleCombine( second.env );
1620                                OpenVarSet openVars;
1621                                AssertionSet needAssertions, haveAssertions;
1622                                Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
1623                                Type* commonType = nullptr;
1624                                if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1625                                        RangeExpr * newExpr = new RangeExpr( first.expr->clone(), second.expr->clone() );
1626                                        newExpr->result = commonType ? commonType : first.expr->result->clone();
1627                                        newAlt.expr = newExpr;
1628                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1629                                } // if
1630                        } // for
1631                } // for
1632        }
1633
1634        void AlternativeFinder::Finder::postvisit( UntypedTupleExpr *tupleExpr ) {
1635                std::vector< AlternativeFinder > subExprAlternatives;
1636                altFinder.findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
1637                        back_inserter( subExprAlternatives ) );
1638                std::vector< AltList > possibilities;
1639                combos( subExprAlternatives.begin(), subExprAlternatives.end(),
1640                        back_inserter( possibilities ) );
1641                for ( const AltList& alts : possibilities ) {
1642                        std::list< Expression * > exprs;
1643                        makeExprList( alts, exprs );
1644
1645                        TypeEnvironment compositeEnv;
1646                        simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
1647                        alternatives.push_back(
1648                                Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
1649                } // for
1650        }
1651
1652        void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
1653                alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1654        }
1655
1656        void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
1657                alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
1658        }
1659
1660        void AlternativeFinder::Finder::postvisit( ConstructorExpr * ctorExpr ) {
1661                AlternativeFinder finder( indexer, env );
1662                // don't prune here, since it's guaranteed all alternatives will have the same type
1663                // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
1664                finder.findWithoutPrune( ctorExpr->get_callExpr() );
1665                for ( Alternative & alt : finder.alternatives ) {
1666                        alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
1667                }
1668        }
1669
1670        void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
1671                alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1672        }
1673
1674        void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
1675                alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
1676        }
1677
1678        void AlternativeFinder::Finder::postvisit( UniqueExpr *unqExpr ) {
1679                AlternativeFinder finder( indexer, env );
1680                finder.findWithAdjustment( unqExpr->get_expr() );
1681                for ( Alternative & alt : finder.alternatives ) {
1682                        // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
1683                        UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
1684                        alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
1685                }
1686        }
1687
1688        void AlternativeFinder::Finder::postvisit( StmtExpr *stmtExpr ) {
1689                StmtExpr * newStmtExpr = stmtExpr->clone();
1690                ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
1691                // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
1692                alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
1693        }
1694
1695        void AlternativeFinder::Finder::postvisit( UntypedInitExpr *initExpr ) {
1696                // handle each option like a cast
1697                AltList candidates;
1698                PRINT(
1699                        std::cerr << "untyped init expr: " << initExpr << std::endl;
1700                )
1701                // O(N^2) checks of d-types with e-types
1702                for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
1703                        Type * toType = resolveTypeof( initAlt.type->clone(), indexer );
1704                        SymTab::validateType( toType, &indexer );
1705                        adjustExprType( toType, env, indexer );
1706                        // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
1707                        // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
1708                        // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
1709                        AlternativeFinder finder( indexer, env );
1710                        finder.targetType = toType;
1711                        finder.findWithAdjustment( initExpr->expr );
1712                        for ( Alternative & alt : finder.get_alternatives() ) {
1713                                TypeEnvironment newEnv( alt.env );
1714                                AssertionSet needAssertions, haveAssertions;
1715                                OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
1716                                PRINT(
1717                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
1718                                )
1719                                // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
1720                                // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
1721                                // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
1722                                // to.
1723                                int discardedValues = alt.expr->result->size() - toType->size();
1724                                if ( discardedValues < 0 ) continue;
1725                                // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1726                                // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1727                                // unification run for side-effects
1728                                unify( toType, alt.expr->result, newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
1729
1730                                Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
1731                                if ( thisCost != Cost::infinity ) {
1732                                        // count one safe conversion for each value that is thrown away
1733                                        thisCost.incSafe( discardedValues );
1734                                        Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
1735                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
1736                                }
1737                        }
1738                }
1739
1740                // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1741                // cvtCost member to the cost member (since the old cost is now irrelevant).  Thus, calling findMinCost twice
1742                // selects first based on argument cost, then on conversion cost.
1743                AltList minArgCost;
1744                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1745                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1746        }
1747
1748        void AlternativeFinder::Finder::postvisit( InitExpr * ) {
1749                assertf( false, "AlternativeFinder should never see a resolved InitExpr." );
1750        }
1751
1752        void AlternativeFinder::Finder::postvisit( DeletedExpr * ) {
1753                assertf( false, "AlternativeFinder should never see a DeletedExpr." );
1754        }
1755} // namespace ResolvExpr
1756
1757// Local Variables: //
1758// tab-width: 4 //
1759// mode: c++ //
1760// compile-command: "make install" //
1761// End: //
Note: See TracBrowser for help on using the repository browser.