source: src/ResolvExpr/AlternativeFinder.cc @ 6d6e829

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resnenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprno_listpersistent-indexerpthread-emulationqualifiedEnum
Last change on this file since 6d6e829 was 6d6e829, checked in by Aaron Moss <a3moss@…>, 6 years ago

First compiling draft of deferred assertions (build failure)

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