source: src/ResolvExpr/AlternativeFinder.cc @ a94b829

aaron-thesisarm-ehcleanup-dtorsdeferred_resndemanglerjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerresolv-newwith_gc
Last change on this file since a94b829 was a94b829, checked in by Aaron Moss <a3moss@…>, 4 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

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