source: src/ResolvExpr/AlternativeFinder.cc @ 4b6ef70

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since 4b6ef70 was 4b6ef70, checked in by Aaron Moss <a3moss@…>, 8 years ago

Fix one tuple bug in resolver refactor

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