source: src/ResolvExpr/AlternativeFinder.cc @ 92fea32

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumwith_gc
Last change on this file since 92fea32 was a16764a6, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

Changed warning system to prepare for toggling warnings

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