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

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 6bbce58 was d29fa5f, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

Remove has_result

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