source: src/ResolvExpr/AlternativeFinder.cc @ f22b7aef

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since f22b7aef was ddf8a29, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

Refactor computeConversionCost, apply conversions to ConditionalExpr? arguments, re-add Werror to libcfa build

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