Changeset 153d3440


Ignore:
Timestamp:
Apr 12, 2023, 10:42:12 AM (20 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
ADT, ast-experimental, master
Children:
eb8d791
Parents:
94c98f0e
Message:

Reorganize CandidateFinder? to lower indentation. I did not flatten the anonymous namespace because there is a lot both inside and outside it.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/CandidateFinder.cpp

    r94c98f0e r153d3440  
    5555namespace ResolvExpr {
    5656
     57/// Unique identifier for matching expression resolutions to their requesting expression
     58UniqueId globalResnSlot = 0;
     59
     60namespace {
     61        /// First index is which argument, second is which alternative, third is which exploded element
     62        using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
     63
     64        /// Returns a list of alternatives with the minimum cost in the given list
     65        CandidateList findMinCost( const CandidateList & candidates ) {
     66                CandidateList out;
     67                Cost minCost = Cost::infinity;
     68                for ( const CandidateRef & r : candidates ) {
     69                        if ( r->cost < minCost ) {
     70                                minCost = r->cost;
     71                                out.clear();
     72                                out.emplace_back( r );
     73                        } else if ( r->cost == minCost ) {
     74                                out.emplace_back( r );
     75                        }
     76                }
     77                return out;
     78        }
     79
     80        /// Computes conversion cost for a given expression to a given type
     81        const ast::Expr * computeExpressionConversionCost(
     82                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
     83        ) {
     84                Cost convCost = computeConversionCost(
     85                                arg->result, paramType, arg->get_lvalue(), symtab, env );
     86                outCost += convCost;
     87
     88                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
     89                // conversion. Ignore poly cost for now, since this requires resolution of the cast to
     90                // infer parameters and this does not currently work for the reason stated below
     91                Cost tmpCost = convCost;
     92                tmpCost.incPoly( -tmpCost.get_polyCost() );
     93                if ( tmpCost != Cost::zero ) {
     94                        ast::ptr< ast::Type > newType = paramType;
     95                        env.apply( newType );
     96                        return new ast::CastExpr{ arg, newType };
     97
     98                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     99                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
     100                        // once this is fixed it should be possible to resolve the cast.
     101                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
     102                        // but it shouldn't be because this makes the conversion from DT* to DT* since
     103                        // commontype(zero_t, DT*) is DT*, rather than nothing
     104
     105                        // CandidateFinder finder{ symtab, env };
     106                        // finder.find( arg, ResolvMode::withAdjustment() );
     107                        // assertf( finder.candidates.size() > 0,
     108                        //      "Somehow castable expression failed to find alternatives." );
     109                        // assertf( finder.candidates.size() == 1,
     110                        //      "Somehow got multiple alternatives for known cast expression." );
     111                        // return finder.candidates.front()->expr;
     112                }
     113
     114                return arg;
     115        }
     116
     117        /// Computes conversion cost for a given candidate
     118        Cost computeApplicationConversionCost(
     119                CandidateRef cand, const ast::SymbolTable & symtab
     120        ) {
     121                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     122                auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     123                auto function = pointer->base.strict_as< ast::FunctionType >();
     124
     125                Cost convCost = Cost::zero;
     126                const auto & params = function->params;
     127                auto param = params.begin();
     128                auto & args = appExpr->args;
     129
     130                for ( unsigned i = 0; i < args.size(); ++i ) {
     131                        const ast::Type * argType = args[i]->result;
     132                        PRINT(
     133                                std::cerr << "arg expression:" << std::endl;
     134                                ast::print( std::cerr, args[i], 2 );
     135                                std::cerr << "--- results are" << std::endl;
     136                                ast::print( std::cerr, argType, 2 );
     137                        )
     138
     139                        if ( param == params.end() ) {
     140                                if ( function->isVarArgs ) {
     141                                        convCost.incUnsafe();
     142                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
     143                                                << convCost << std::endl; ; )
     144                                        // convert reference-typed expressions into value-typed expressions
     145                                        cand->expr = ast::mutate_field_index(
     146                                                appExpr, &ast::ApplicationExpr::args, i,
     147                                                referenceToRvalueConversion( args[i], convCost ) );
     148                                        continue;
     149                                } else return Cost::infinity;
     150                        }
     151
     152                        if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {
     153                                // Default arguments should be free - don't include conversion cost.
     154                                // Unwrap them here because they are not relevant to the rest of the system
     155                                cand->expr = ast::mutate_field_index(
     156                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
     157                                ++param;
     158                                continue;
     159                        }
     160
     161                        // mark conversion cost and also specialization cost of param type
     162                        // const ast::Type * paramType = (*param)->get_type();
     163                        cand->expr = ast::mutate_field_index(
     164                                appExpr, &ast::ApplicationExpr::args, i,
     165                                computeExpressionConversionCost(
     166                                        args[i], *param, symtab, cand->env, convCost ) );
     167                        convCost.decSpec( specCost( *param ) );
     168                        ++param;  // can't be in for-loop update because of the continue
     169                }
     170
     171                if ( param != params.end() ) return Cost::infinity;
     172
     173                // specialization cost of return types can't be accounted for directly, it disables
     174                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
     175                //
     176                //   forall(otype OS) {
     177                //     void ?|?(OS&, int);  // with newline
     178                //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
     179                //   }
     180
     181                // mark type variable and specialization cost of forall clause
     182                convCost.incVar( function->forall.size() );
     183                convCost.decSpec( function->assertions.size() );
     184
     185                return convCost;
     186        }
     187
     188        void makeUnifiableVars(
     189                const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
     190                ast::AssertionSet & need
     191        ) {
     192                for ( auto & tyvar : type->forall ) {
     193                        unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
     194                }
     195                for ( auto & assn : type->assertions ) {
     196                        need[ assn ].isUsed = true;
     197                }
     198        }
     199
     200        /// Gets a default value from an initializer, nullptr if not present
     201        const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {
     202                if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {
     203                        if ( auto ce = si->value.as< ast::CastExpr >() ) {
     204                                return ce->arg.as< ast::ConstantExpr >();
     205                        } else {
     206                                return si->value.as< ast::ConstantExpr >();
     207                        }
     208                }
     209                return nullptr;
     210        }
     211
     212        /// State to iteratively build a match of parameter expressions to arguments
     213        struct ArgPack {
     214                std::size_t parent;          ///< Index of parent pack
     215                ast::ptr< ast::Expr > expr;  ///< The argument stored here
     216                Cost cost;                   ///< The cost of this argument
     217                ast::TypeEnvironment env;    ///< Environment for this pack
     218                ast::AssertionSet need;      ///< Assertions outstanding for this pack
     219                ast::AssertionSet have;      ///< Assertions found for this pack
     220                ast::OpenVarSet open;        ///< Open variables for this pack
     221                unsigned nextArg;            ///< Index of next argument in arguments list
     222                unsigned tupleStart;         ///< Number of tuples that start at this index
     223                unsigned nextExpl;           ///< Index of next exploded element
     224                unsigned explAlt;            ///< Index of alternative for nextExpl > 0
     225
     226                ArgPack()
     227                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
     228                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     229
     230                ArgPack(
     231                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
     232                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
     233                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
     234                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     235
     236                ArgPack(
     237                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     238                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     239                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
     240                        unsigned nextExpl = 0, unsigned explAlt = 0 )
     241                : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
     242                  have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
     243                  nextExpl( nextExpl ), explAlt( explAlt ) {}
     244
     245                ArgPack(
     246                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
     247                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
     248                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
     249                  need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
     250                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
     251
     252                /// true if this pack is in the middle of an exploded argument
     253                bool hasExpl() const { return nextExpl > 0; }
     254
     255                /// Gets the list of exploded candidates for this pack
     256                const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
     257                        return args[ nextArg-1 ][ explAlt ];
     258                }
     259
     260                /// Ends a tuple expression, consolidating the appropriate args
     261                void endTuple( const std::vector< ArgPack > & packs ) {
     262                        // add all expressions in tuple to list, summing cost
     263                        std::deque< const ast::Expr * > exprs;
     264                        const ArgPack * pack = this;
     265                        if ( expr ) { exprs.emplace_front( expr ); }
     266                        while ( pack->tupleStart == 0 ) {
     267                                pack = &packs[pack->parent];
     268                                exprs.emplace_front( pack->expr );
     269                                cost += pack->cost;
     270                        }
     271                        // reset pack to appropriate tuple
     272                        std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
     273                        expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
     274                        tupleStart = pack->tupleStart - 1;
     275                        parent = pack->parent;
     276                }
     277        };
     278
     279        /// Instantiates an argument to match a parameter, returns false if no matching results left
     280        bool instantiateArgument(
     281                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
     282                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
     283                unsigned nTuples = 0
     284        ) {
     285                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     286                        // paramType is a TupleType -- group args into a TupleExpr
     287                        ++nTuples;
     288                        for ( const ast::Type * type : *tupleType ) {
     289                                // xxx - dropping initializer changes behaviour from previous, but seems correct
     290                                // ^^^ need to handle the case where a tuple has a default argument
     291                                if ( ! instantiateArgument(
     292                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
     293                                nTuples = 0;
     294                        }
     295                        // re-constitute tuples for final generation
     296                        for ( auto i = genStart; i < results.size(); ++i ) {
     297                                results[i].endTuple( results );
     298                        }
     299                        return true;
     300                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
     301                        // paramType is a ttype, consumes all remaining arguments
     302
     303                        // completed tuples; will be spliced to end of results to finish
     304                        std::vector< ArgPack > finalResults{};
     305
     306                        // iterate until all results completed
     307                        std::size_t genEnd;
     308                        ++nTuples;
     309                        do {
     310                                genEnd = results.size();
     311
     312                                // add another argument to results
     313                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     314                                        unsigned nextArg = results[i].nextArg;
     315
     316                                        // use next element of exploded tuple if present
     317                                        if ( results[i].hasExpl() ) {
     318                                                const ExplodedArg & expl = results[i].getExpl( args );
     319
     320                                                unsigned nextExpl = results[i].nextExpl + 1;
     321                                                if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     322
     323                                                results.emplace_back(
     324                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
     325                                                        copy( results[i].need ), copy( results[i].have ),
     326                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
     327                                                        results[i].explAlt );
     328
     329                                                continue;
     330                                        }
     331
     332                                        // finish result when out of arguments
     333                                        if ( nextArg >= args.size() ) {
     334                                                ArgPack newResult{
     335                                                        results[i].env, results[i].need, results[i].have, results[i].open };
     336                                                newResult.nextArg = nextArg;
     337                                                const ast::Type * argType = nullptr;
     338
     339                                                if ( nTuples > 0 || ! results[i].expr ) {
     340                                                        // first iteration or no expression to clone,
     341                                                        // push empty tuple expression
     342                                                        newResult.parent = i;
     343                                                        newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
     344                                                        argType = newResult.expr->result;
     345                                                } else {
     346                                                        // clone result to collect tuple
     347                                                        newResult.parent = results[i].parent;
     348                                                        newResult.cost = results[i].cost;
     349                                                        newResult.tupleStart = results[i].tupleStart;
     350                                                        newResult.expr = results[i].expr;
     351                                                        argType = newResult.expr->result;
     352
     353                                                        if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
     354                                                                // the case where a ttype value is passed directly is special,
     355                                                                // e.g. for argument forwarding purposes
     356                                                                // xxx - what if passing multiple arguments, last of which is
     357                                                                //       ttype?
     358                                                                // xxx - what would happen if unify was changed so that unifying
     359                                                                //       tuple
     360                                                                // types flattened both before unifying lists? then pass in
     361                                                                // TupleType (ttype) below.
     362                                                                --newResult.tupleStart;
     363                                                        } else {
     364                                                                // collapse leftover arguments into tuple
     365                                                                newResult.endTuple( results );
     366                                                                argType = newResult.expr->result;
     367                                                        }
     368                                                }
     369
     370                                                // check unification for ttype before adding to final
     371                                                if (
     372                                                        unify(
     373                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
     374                                                                newResult.open, symtab )
     375                                                ) {
     376                                                        finalResults.emplace_back( std::move( newResult ) );
     377                                                }
     378
     379                                                continue;
     380                                        }
     381
     382                                        // add each possible next argument
     383                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     384                                                const ExplodedArg & expl = args[nextArg][j];
     385
     386                                                // fresh copies of parent parameters for this iteration
     387                                                ast::TypeEnvironment env = results[i].env;
     388                                                ast::OpenVarSet open = results[i].open;
     389
     390                                                env.addActual( expl.env, open );
     391
     392                                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     393                                                if ( expl.exprs.empty() ) {
     394                                                        results.emplace_back(
     395                                                                results[i], std::move( env ), copy( results[i].need ),
     396                                                                copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
     397
     398                                                        continue;
     399                                                }
     400
     401                                                // add new result
     402                                                results.emplace_back(
     403                                                        i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
     404                                                        copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
     405                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
     406                                        }
     407                                }
     408
     409                                // reset for next round
     410                                genStart = genEnd;
     411                                nTuples = 0;
     412                        } while ( genEnd != results.size() );
     413
     414                        // splice final results onto results
     415                        for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
     416                                results.emplace_back( std::move( finalResults[i] ) );
     417                        }
     418                        return ! finalResults.empty();
     419                }
     420
     421                // iterate each current subresult
     422                std::size_t genEnd = results.size();
     423                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     424                        unsigned nextArg = results[i].nextArg;
     425
     426                        // use remainder of exploded tuple if present
     427                        if ( results[i].hasExpl() ) {
     428                                const ExplodedArg & expl = results[i].getExpl( args );
     429                                const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];
     430
     431                                ast::TypeEnvironment env = results[i].env;
     432                                ast::AssertionSet need = results[i].need, have = results[i].have;
     433                                ast::OpenVarSet open = results[i].open;
     434
     435                                const ast::Type * argType = expr->result;
     436
     437                                PRINT(
     438                                        std::cerr << "param type is ";
     439                                        ast::print( std::cerr, paramType );
     440                                        std::cerr << std::endl << "arg type is ";
     441                                        ast::print( std::cerr, argType );
     442                                        std::cerr << std::endl;
     443                                )
     444
     445                                if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     446                                        unsigned nextExpl = results[i].nextExpl + 1;
     447                                        if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     448
     449                                        results.emplace_back(
     450                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
     451                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
     452                                }
     453
     454                                continue;
     455                        }
     456
     457                        // use default initializers if out of arguments
     458                        if ( nextArg >= args.size() ) {
     459                                if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {
     460                                        ast::TypeEnvironment env = results[i].env;
     461                                        ast::AssertionSet need = results[i].need, have = results[i].have;
     462                                        ast::OpenVarSet open = results[i].open;
     463
     464                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
     465                                                results.emplace_back(
     466                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
     467                                                        std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
     468                                        }
     469                                }
     470
     471                                continue;
     472                        }
     473
     474                        // Check each possible next argument
     475                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     476                                const ExplodedArg & expl = args[nextArg][j];
     477
     478                                // fresh copies of parent parameters for this iteration
     479                                ast::TypeEnvironment env = results[i].env;
     480                                ast::AssertionSet need = results[i].need, have = results[i].have;
     481                                ast::OpenVarSet open = results[i].open;
     482
     483                                env.addActual( expl.env, open );
     484
     485                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     486                                if ( expl.exprs.empty() ) {
     487                                        results.emplace_back(
     488                                                results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     489                                                nextArg + 1, expl.cost );
     490
     491                                        continue;
     492                                }
     493
     494                                // consider only first exploded arg
     495                                const ast::Expr * expr = expl.exprs.front();
     496                                const ast::Type * argType = expr->result;
     497
     498                                PRINT(
     499                                        std::cerr << "param type is ";
     500                                        ast::print( std::cerr, paramType );
     501                                        std::cerr << std::endl << "arg type is ";
     502                                        ast::print( std::cerr, argType );
     503                                        std::cerr << std::endl;
     504                                )
     505
     506                                // attempt to unify types
     507                                if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     508                                        // add new result
     509                                        results.emplace_back(
     510                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     511                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
     512                                }
     513                        }
     514                }
     515
     516                // reset for next parameter
     517                genStart = genEnd;
     518
     519                return genEnd != results.size();  // were any new results added?
     520        }
     521
     522        /// Generate a cast expression from `arg` to `toType`
     523        const ast::Expr * restructureCast(
     524                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
     525        ) {
     526                if (
     527                        arg->result->size() > 1
     528                        && ! toType->isVoid()
     529                        && ! dynamic_cast< const ast::ReferenceType * >( toType )
     530                ) {
     531                        // Argument is a tuple and the target type is neither void nor a reference. Cast each
     532                        // member of the tuple to its corresponding target type, producing the tuple of those
     533                        // cast expressions. If there are more components of the tuple than components in the
     534                        // target type, then excess components do not come out in the result expression (but
     535                        // UniqueExpr ensures that the side effects will still be produced)
     536                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
     537                                // expressions which may contain side effects require a single unique instance of
     538                                // the expression
     539                                arg = new ast::UniqueExpr{ arg->location, arg };
     540                        }
     541                        std::vector< ast::ptr< ast::Expr > > components;
     542                        for ( unsigned i = 0; i < toType->size(); ++i ) {
     543                                // cast each component
     544                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
     545                                components.emplace_back(
     546                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
     547                        }
     548                        return new ast::TupleExpr{ arg->location, std::move( components ) };
     549                } else {
     550                        // handle normally
     551                        return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
     552                }
     553        }
     554
     555        /// Gets the name from an untyped member expression (must be NameExpr)
     556        const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
     557                if ( memberExpr->member.as< ast::ConstantExpr >() ) {
     558                        SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
     559                }
     560
     561                return memberExpr->member.strict_as< ast::NameExpr >()->name;
     562        }
     563
     564        /// Actually visits expressions to find their candidate interpretations
     565        class Finder final : public ast::WithShortCircuiting {
     566                const ResolveContext & context;
     567                const ast::SymbolTable & symtab;
     568        public:
     569                // static size_t traceId;
     570                CandidateFinder & selfFinder;
     571                CandidateList & candidates;
     572                const ast::TypeEnvironment & tenv;
     573                ast::ptr< ast::Type > & targetType;
     574
     575                enum Errors {
     576                        NotFound,
     577                        NoMatch,
     578                        ArgsToFew,
     579                        ArgsToMany,
     580                        RetsToFew,
     581                        RetsToMany,
     582                        NoReason
     583                };
     584
     585                struct {
     586                        Errors code = NotFound;
     587                } reason;
     588
     589                Finder( CandidateFinder & f )
     590                : context( f.context ), symtab( context.symtab ), selfFinder( f ),
     591                  candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
     592
     593                void previsit( const ast::Node * ) { visit_children = false; }
     594
     595                /// Convenience to add candidate to list
     596                template<typename... Args>
     597                void addCandidate( Args &&... args ) {
     598                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
     599                        reason.code = NoReason;
     600                }
     601
     602                void postvisit( const ast::ApplicationExpr * applicationExpr ) {
     603                        addCandidate( applicationExpr, tenv );
     604                }
     605
     606                /// Set up candidate assertions for inference
     607                void inferParameters( CandidateRef & newCand, CandidateList & out );
     608
     609                /// Completes a function candidate with arguments located
     610                void validateFunctionCandidate(
     611                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     612                        CandidateList & out );
     613
     614                /// Builds a list of candidates for a function, storing them in out
     615                void makeFunctionCandidates(
     616                        const CandidateRef & func, const ast::FunctionType * funcType,
     617                        const ExplodedArgs_new & args, CandidateList & out );
     618
     619                /// Adds implicit struct-conversions to the alternative list
     620                void addAnonConversions( const CandidateRef & cand );
     621
     622                /// Adds aggregate member interpretations
     623                void addAggMembers(
     624                        const ast::BaseInstType * aggrInst, const ast::Expr * expr,
     625                        const Candidate & cand, const Cost & addedCost, const std::string & name
     626                );
     627
     628                /// Adds tuple member interpretations
     629                void addTupleMembers(
     630                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     631                        const Cost & addedCost, const ast::Expr * member
     632                );
     633
     634                /// true if expression is an lvalue
     635                static bool isLvalue( const ast::Expr * x ) {
     636                        return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
     637                }
     638
     639                void postvisit( const ast::UntypedExpr * untypedExpr );
     640                void postvisit( const ast::VariableExpr * variableExpr );
     641                void postvisit( const ast::ConstantExpr * constantExpr );
     642                void postvisit( const ast::SizeofExpr * sizeofExpr );
     643                void postvisit( const ast::AlignofExpr * alignofExpr );
     644                void postvisit( const ast::AddressExpr * addressExpr );
     645                void postvisit( const ast::LabelAddressExpr * labelExpr );
     646                void postvisit( const ast::CastExpr * castExpr );
     647                void postvisit( const ast::VirtualCastExpr * castExpr );
     648                void postvisit( const ast::KeywordCastExpr * castExpr );
     649                void postvisit( const ast::UntypedMemberExpr * memberExpr );
     650                void postvisit( const ast::MemberExpr * memberExpr );
     651                void postvisit( const ast::NameExpr * nameExpr );
     652                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr );
     653                void postvisit( const ast::OffsetofExpr * offsetofExpr );
     654                void postvisit( const ast::OffsetPackExpr * offsetPackExpr );
     655                void postvisit( const ast::LogicalExpr * logicalExpr );
     656                void postvisit( const ast::ConditionalExpr * conditionalExpr );
     657                void postvisit( const ast::CommaExpr * commaExpr );
     658                void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr );
     659                void postvisit( const ast::ConstructorExpr * ctorExpr );
     660                void postvisit( const ast::RangeExpr * rangeExpr );
     661                void postvisit( const ast::UntypedTupleExpr * tupleExpr );
     662                void postvisit( const ast::TupleExpr * tupleExpr );
     663                void postvisit( const ast::TupleIndexExpr * tupleExpr );
     664                void postvisit( const ast::TupleAssignExpr * tupleExpr );
     665                void postvisit( const ast::UniqueExpr * unqExpr );
     666                void postvisit( const ast::StmtExpr * stmtExpr );
     667                void postvisit( const ast::UntypedInitExpr * initExpr );
     668
     669                void postvisit( const ast::InitExpr * ) {
     670                        assertf( false, "CandidateFinder should never see a resolved InitExpr." );
     671                }
     672
     673                void postvisit( const ast::DeletedExpr * ) {
     674                        assertf( false, "CandidateFinder should never see a DeletedExpr." );
     675                }
     676
     677                void postvisit( const ast::GenericExpr * ) {
     678                        assertf( false, "_Generic is not yet supported." );
     679                }
     680        };
     681
     682        /// Set up candidate assertions for inference
     683        void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) {
     684                // Set need bindings for any unbound assertions
     685                UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
     686                for ( auto & assn : newCand->need ) {
     687                        // skip already-matched assertions
     688                        if ( assn.second.resnSlot != 0 ) continue;
     689                        // assign slot for expression if needed
     690                        if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
     691                        // fix slot to assertion
     692                        assn.second.resnSlot = crntResnSlot;
     693                }
     694                // pair slot to expression
     695                if ( crntResnSlot != 0 ) {
     696                        newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );
     697                }
     698
     699                // add to output list; assertion satisfaction will occur later
     700                out.emplace_back( newCand );
     701        }
     702
     703        /// Completes a function candidate with arguments located
     704        void Finder::validateFunctionCandidate(
     705                const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     706                CandidateList & out
     707        ) {
     708                ast::ApplicationExpr * appExpr =
     709                        new ast::ApplicationExpr{ func->expr->location, func->expr };
     710                // sum cost and accumulate arguments
     711                std::deque< const ast::Expr * > args;
     712                Cost cost = func->cost;
     713                const ArgPack * pack = &result;
     714                while ( pack->expr ) {
     715                        args.emplace_front( pack->expr );
     716                        cost += pack->cost;
     717                        pack = &results[pack->parent];
     718                }
     719                std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
     720                appExpr->args = std::move( vargs );
     721                // build and validate new candidate
     722                auto newCand =
     723                        std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
     724                PRINT(
     725                        std::cerr << "instantiate function success: " << appExpr << std::endl;
     726                        std::cerr << "need assertions:" << std::endl;
     727                        ast::print( std::cerr, result.need, 2 );
     728                )
     729                inferParameters( newCand, out );
     730        }
     731
     732        /// Builds a list of candidates for a function, storing them in out
     733        void Finder::makeFunctionCandidates(
     734                const CandidateRef & func, const ast::FunctionType * funcType,
     735                const ExplodedArgs_new & args, CandidateList & out
     736        ) {
     737                ast::OpenVarSet funcOpen;
     738                ast::AssertionSet funcNeed, funcHave;
     739                ast::TypeEnvironment funcEnv{ func->env };
     740                makeUnifiableVars( funcType, funcOpen, funcNeed );
     741                // add all type variables as open variables now so that those not used in the
     742                // parameter list are still considered open
     743                funcEnv.add( funcType->forall );
     744
     745                if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
     746                        // attempt to narrow based on expected target type
     747                        const ast::Type * returnType = funcType->returns.front();
     748                        if ( ! unify(
     749                                returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     750                        ) {
     751                                // unification failed, do not pursue this candidate
     752                                return;
     753                        }
     754                }
     755
     756                // iteratively build matches, one parameter at a time
     757                std::vector< ArgPack > results;
     758                results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );
     759                std::size_t genStart = 0;
     760
     761                // xxx - how to handle default arg after change to ftype representation?
     762                if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
     763                        if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
     764                                // function may have default args only if directly calling by name
     765                                // must use types on candidate however, due to RenameVars substitution
     766                                auto nParams = funcType->params.size();
     767
     768                                for (size_t i=0; i<nParams; ++i) {
     769                                        auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
     770                                        if (!instantiateArgument(
     771                                                funcType->params[i], obj->init, args, results, genStart, symtab)) return;
     772                                }
     773                                goto endMatch;
     774                        }
     775                }
     776                for ( const auto & param : funcType->params ) {
     777                        // Try adding the arguments corresponding to the current parameter to the existing
     778                        // matches
     779                        // no default args for indirect calls
     780                        if ( ! instantiateArgument(
     781                                param, nullptr, args, results, genStart, symtab ) ) return;
     782                }
     783
     784                endMatch:
     785                if ( funcType->isVarArgs ) {
     786                        // append any unused arguments to vararg pack
     787                        std::size_t genEnd;
     788                        do {
     789                                genEnd = results.size();
     790
     791                                // iterate results
     792                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     793                                        unsigned nextArg = results[i].nextArg;
     794
     795                                        // use remainder of exploded tuple if present
     796                                        if ( results[i].hasExpl() ) {
     797                                                const ExplodedArg & expl = results[i].getExpl( args );
     798
     799                                                unsigned nextExpl = results[i].nextExpl + 1;
     800                                                if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     801
     802                                                results.emplace_back(
     803                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
     804                                                        copy( results[i].need ), copy( results[i].have ),
     805                                                        copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,
     806                                                        results[i].explAlt );
     807
     808                                                continue;
     809                                        }
     810
     811                                        // finish result when out of arguments
     812                                        if ( nextArg >= args.size() ) {
     813                                                validateFunctionCandidate( func, results[i], results, out );
     814
     815                                                continue;
     816                                        }
     817
     818                                        // add each possible next argument
     819                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     820                                                const ExplodedArg & expl = args[nextArg][j];
     821
     822                                                // fresh copies of parent parameters for this iteration
     823                                                ast::TypeEnvironment env = results[i].env;
     824                                                ast::OpenVarSet open = results[i].open;
     825
     826                                                env.addActual( expl.env, open );
     827
     828                                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     829                                                if ( expl.exprs.empty() ) {
     830                                                        results.emplace_back(
     831                                                                results[i], std::move( env ), copy( results[i].need ),
     832                                                                copy( results[i].have ), std::move( open ), nextArg + 1,
     833                                                                expl.cost );
     834
     835                                                        continue;
     836                                                }
     837
     838                                                // add new result
     839                                                results.emplace_back(
     840                                                        i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
     841                                                        copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
     842                                                        expl.exprs.size() == 1 ? 0 : 1, j );
     843                                        }
     844                                }
     845
     846                                genStart = genEnd;
     847                        } while( genEnd != results.size() );
     848                } else {
     849                        // filter out the results that don't use all the arguments
     850                        for ( std::size_t i = genStart; i < results.size(); ++i ) {
     851                                ArgPack & result = results[i];
     852                                if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
     853                                        validateFunctionCandidate( func, result, results, out );
     854                                }
     855                        }
     856                }
     857        }
     858
     859        /// Adds implicit struct-conversions to the alternative list
     860        void Finder::addAnonConversions( const CandidateRef & cand ) {
     861                // adds anonymous member interpretations whenever an aggregate value type is seen.
     862                // it's okay for the aggregate expression to have reference type -- cast it to the
     863                // base type to treat the aggregate as the referenced value
     864                ast::ptr< ast::Expr > aggrExpr( cand->expr );
     865                ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
     866                cand->env.apply( aggrType );
     867
     868                if ( aggrType.as< ast::ReferenceType >() ) {
     869                        aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     870                }
     871
     872                if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
     873                        addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
     874                } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
     875                        addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
     876                }
     877        }
     878
     879        /// Adds aggregate member interpretations
     880        void Finder::addAggMembers(
     881                const ast::BaseInstType * aggrInst, const ast::Expr * expr,
     882                const Candidate & cand, const Cost & addedCost, const std::string & name
     883        ) {
     884                for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
     885                        auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
     886                        CandidateRef newCand = std::make_shared<Candidate>(
     887                                cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
     888                        // add anonymous member interpretations whenever an aggregate value type is seen
     889                        // as a member expression
     890                        addAnonConversions( newCand );
     891                        candidates.emplace_back( std::move( newCand ) );
     892                }
     893        }
     894
     895        /// Adds tuple member interpretations
     896        void Finder::addTupleMembers(
     897                const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     898                const Cost & addedCost, const ast::Expr * member
     899        ) {
     900                if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
     901                        // get the value of the constant expression as an int, must be between 0 and the
     902                        // length of the tuple to have meaning
     903                        long long val = constantExpr->intValue();
     904                        if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
     905                                addCandidate(
     906                                        cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
     907                                        addedCost );
     908                        }
     909                }
     910        }
     911
     912        void Finder::postvisit( const ast::UntypedExpr * untypedExpr ) {
     913                std::vector< CandidateFinder > argCandidates =
     914                        selfFinder.findSubExprs( untypedExpr->args );
     915
     916                // take care of possible tuple assignments
     917                // if not tuple assignment, handled as normal function call
     918                Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
     919
     920                CandidateFinder funcFinder( context, tenv );
     921                if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
     922                        auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     923                        if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
     924                                assertf(!argCandidates.empty(), "special function call without argument");
     925                                for (auto & firstArgCand: argCandidates[0]) {
     926                                        ast::ptr<ast::Type> argType = firstArgCand->expr->result;
     927                                        firstArgCand->env.apply(argType);
     928                                        // strip references
     929                                        // xxx - is this correct?
     930                                        while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
     931
     932                                        // convert 1-tuple to plain type
     933                                        if (auto tuple = argType.as<ast::TupleType>()) {
     934                                                if (tuple->size() == 1) {
     935                                                        argType = tuple->types[0];
     936                                                }
     937                                        }
     938
     939                                        // if argType is an unbound type parameter, all special functions need to be searched.
     940                                        if (isUnboundType(argType)) {
     941                                                funcFinder.otypeKeys.clear();
     942                                                break;
     943                                        }
     944
     945                                        if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
     946                                        // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
     947                                        //      const ast::EnumDecl * enumDecl = enumInst->base; // Here
     948                                        //      if ( const ast::Type* enumType = enumDecl->base ) {
     949                                        //              // instance of enum (T) is a instance of type (T)
     950                                        //              funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
     951                                        //      } else {
     952                                        //              // instance of an untyped enum is techically int
     953                                        //              funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
     954                                        //      }
     955                                        // }
     956                                        else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
     957                                }
     958                        }
     959                }
     960                // if candidates are already produced, do not fail
     961                // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
     962                // this means there exists ctor/assign functions with a tuple as first parameter.
     963                ResolvMode mode = {
     964                        true, // adjust
     965                        !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
     966                        selfFinder.candidates.empty() // failfast if other options are not found
     967                };
     968                funcFinder.find( untypedExpr->func, mode );
     969                // short-circuit if no candidates
     970                // if ( funcFinder.candidates.empty() ) return;
     971
     972                reason.code = NoMatch;
     973
     974                // find function operators
     975                ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
     976                CandidateFinder opFinder( context, tenv );
     977                // okay if there aren't any function operations
     978                opFinder.find( opExpr, ResolvMode::withoutFailFast() );
     979                PRINT(
     980                        std::cerr << "known function ops:" << std::endl;
     981                        print( std::cerr, opFinder.candidates, 1 );
     982                )
     983
     984                // pre-explode arguments
     985                ExplodedArgs_new argExpansions;
     986                for ( const CandidateFinder & args : argCandidates ) {
     987                        argExpansions.emplace_back();
     988                        auto & argE = argExpansions.back();
     989                        for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
     990                }
     991
     992                // Find function matches
     993                CandidateList found;
     994                SemanticErrorException errors;
     995                for ( CandidateRef & func : funcFinder ) {
     996                        try {
     997                                PRINT(
     998                                        std::cerr << "working on alternative:" << std::endl;
     999                                        print( std::cerr, *func, 2 );
     1000                                )
     1001
     1002                                // check if the type is a pointer to function
     1003                                const ast::Type * funcResult = func->expr->result->stripReferences();
     1004                                if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
     1005                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     1006                                                CandidateRef newFunc{ new Candidate{ *func } };
     1007                                                newFunc->expr =
     1008                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     1009                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     1010                                        }
     1011                                } else if (
     1012                                        auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     1013                                ) {
     1014                                        if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
     1015                                                if ( auto function = clz->bound.as< ast::FunctionType >() ) {
     1016                                                        CandidateRef newFunc{ new Candidate{ *func } };
     1017                                                        newFunc->expr =
     1018                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     1019                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
     1020                                                }
     1021                                        }
     1022                                }
     1023                        } catch ( SemanticErrorException & e ) { errors.append( e ); }
     1024                }
     1025
     1026                // Find matches on function operators `?()`
     1027                if ( ! opFinder.candidates.empty() ) {
     1028                        // add exploded function alternatives to front of argument list
     1029                        std::vector< ExplodedArg > funcE;
     1030                        funcE.reserve( funcFinder.candidates.size() );
     1031                        for ( const CandidateRef & func : funcFinder ) {
     1032                                funcE.emplace_back( *func, symtab );
     1033                        }
     1034                        argExpansions.emplace_front( std::move( funcE ) );
     1035
     1036                        for ( const CandidateRef & op : opFinder ) {
     1037                                try {
     1038                                        // check if type is pointer-to-function
     1039                                        const ast::Type * opResult = op->expr->result->stripReferences();
     1040                                        if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
     1041                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     1042                                                        CandidateRef newOp{ new Candidate{ *op} };
     1043                                                        newOp->expr =
     1044                                                                referenceToRvalueConversion( newOp->expr, newOp->cost );
     1045                                                        makeFunctionCandidates( newOp, function, argExpansions, found );
     1046                                                }
     1047                                        }
     1048                                } catch ( SemanticErrorException & e ) { errors.append( e ); }
     1049                        }
     1050                }
     1051
     1052                // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     1053                // candidates
     1054                if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     1055
     1056                // Compute conversion costs
     1057                for ( CandidateRef & withFunc : found ) {
     1058                        Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
     1059
     1060                        PRINT(
     1061                                auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
     1062                                auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     1063                                auto function = pointer->base.strict_as< ast::FunctionType >();
     1064
     1065                                std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
     1066                                std::cerr << "parameters are:" << std::endl;
     1067                                ast::printAll( std::cerr, function->params, 2 );
     1068                                std::cerr << "arguments are:" << std::endl;
     1069                                ast::printAll( std::cerr, appExpr->args, 2 );
     1070                                std::cerr << "bindings are:" << std::endl;
     1071                                ast::print( std::cerr, withFunc->env, 2 );
     1072                                std::cerr << "cost is: " << withFunc->cost << std::endl;
     1073                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
     1074                        )
     1075
     1076                        if ( cvtCost != Cost::infinity ) {
     1077                                withFunc->cvtCost = cvtCost;
     1078                                candidates.emplace_back( std::move( withFunc ) );
     1079                        }
     1080                }
     1081                found = std::move( candidates );
     1082
     1083                // use a new list so that candidates are not examined by addAnonConversions twice
     1084                CandidateList winners = findMinCost( found );
     1085                promoteCvtCost( winners );
     1086
     1087                // function may return a struct/union value, in which case we need to add candidates
     1088                // for implicit conversions to each of the anonymous members, which must happen after
     1089                // `findMinCost`, since anon conversions are never the cheapest
     1090                for ( const CandidateRef & c : winners ) {
     1091                        addAnonConversions( c );
     1092                }
     1093                spliceBegin( candidates, winners );
     1094
     1095                if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
     1096                        // If resolution is unsuccessful with a target type, try again without, since it
     1097                        // will sometimes succeed when it wouldn't with a target type binding.
     1098                        // For example:
     1099                        //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
     1100                        //   const char * x = "hello world";
     1101                        //   unsigned char ch = x[0];
     1102                        // Fails with simple return type binding (xxx -- check this!) as follows:
     1103                        // * T is bound to unsigned char
     1104                        // * (x: const char *) is unified with unsigned char *, which fails
     1105                        // xxx -- fix this better
     1106                        targetType = nullptr;
     1107                        postvisit( untypedExpr );
     1108                }
     1109        }
     1110
     1111        void Finder::postvisit( const ast::AddressExpr * addressExpr ) {
     1112                CandidateFinder finder( context, tenv );
     1113                finder.find( addressExpr->arg );
     1114
     1115                if ( finder.candidates.empty() ) return;
     1116
     1117                reason.code = NoMatch;
     1118
     1119                for ( CandidateRef & r : finder.candidates ) {
     1120                        if ( ! isLvalue( r->expr ) ) continue;
     1121                        addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
     1122                }
     1123        }
     1124
     1125        void Finder::postvisit( const ast::LabelAddressExpr * labelExpr ) {
     1126                addCandidate( labelExpr, tenv );
     1127        }
     1128
     1129        void Finder::postvisit( const ast::CastExpr * castExpr ) {
     1130                ast::ptr< ast::Type > toType = castExpr->result;
     1131                assert( toType );
     1132                toType = resolveTypeof( toType, context );
     1133                toType = adjustExprType( toType, tenv, symtab );
     1134
     1135                CandidateFinder finder( context, tenv, toType );
     1136                finder.find( castExpr->arg, ResolvMode::withAdjustment() );
     1137
     1138                if ( !finder.candidates.empty() ) reason.code = NoMatch;
     1139
     1140                CandidateList matches;
     1141                for ( CandidateRef & cand : finder.candidates ) {
     1142                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     1143                        ast::OpenVarSet open( cand->open );
     1144
     1145                        cand->env.extractOpenVars( open );
     1146
     1147                        // It is possible that a cast can throw away some values in a multiply-valued
     1148                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
     1149                        // subexpression results that are cast directly. The candidate is invalid if it
     1150                        // has fewer results than there are types to cast to.
     1151                        int discardedValues = cand->expr->result->size() - toType->size();
     1152                        if ( discardedValues < 0 ) continue;
     1153
     1154                        // unification run for side-effects
     1155                        unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
     1156                        Cost thisCost =
     1157                                (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
     1158                                        ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
     1159                                        : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
     1160
     1161                        PRINT(
     1162                                std::cerr << "working on cast with result: " << toType << std::endl;
     1163                                std::cerr << "and expr type: " << cand->expr->result << std::endl;
     1164                                std::cerr << "env: " << cand->env << std::endl;
     1165                        )
     1166                        if ( thisCost != Cost::infinity ) {
     1167                                PRINT(
     1168                                        std::cerr << "has finite cost." << std::endl;
     1169                                )
     1170                                // count one safe conversion for each value that is thrown away
     1171                                thisCost.incSafe( discardedValues );
     1172                                CandidateRef newCand = std::make_shared<Candidate>(
     1173                                        restructureCast( cand->expr, toType, castExpr->isGenerated ),
     1174                                        copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
     1175                                        cand->cost + thisCost );
     1176                                inferParameters( newCand, matches );
     1177                        }
     1178                }
     1179
     1180                // select first on argument cost, then conversion cost
     1181                CandidateList minArgCost = findMinCost( matches );
     1182                promoteCvtCost( minArgCost );
     1183                candidates = findMinCost( minArgCost );
     1184        }
     1185
     1186        void Finder::postvisit( const ast::VirtualCastExpr * castExpr ) {
     1187                assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
     1188                CandidateFinder finder( context, tenv );
     1189                // don't prune here, all alternatives guaranteed to have same type
     1190                finder.find( castExpr->arg, ResolvMode::withoutPrune() );
     1191                for ( CandidateRef & r : finder.candidates ) {
     1192                        addCandidate(
     1193                                *r,
     1194                                new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
     1195                }
     1196        }
     1197
     1198        void Finder::postvisit( const ast::KeywordCastExpr * castExpr ) {
     1199                const auto & loc = castExpr->location;
     1200                assertf( castExpr->result, "Cast target should have been set in Validate." );
     1201                auto ref = castExpr->result.strict_as<ast::ReferenceType>();
     1202                auto inst = ref->base.strict_as<ast::StructInstType>();
     1203                auto target = inst->base.get();
     1204
     1205                CandidateFinder finder( context, tenv );
     1206
     1207                auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
     1208                        for (auto & cand : found) {
     1209                                const ast::Type * expr = cand->expr->result.get();
     1210                                if (expect_ref) {
     1211                                        auto res = dynamic_cast<const ast::ReferenceType*>(expr);
     1212                                        if (!res) { continue; }
     1213                                        expr = res->base.get();
     1214                                }
     1215
     1216                                if (auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
     1217                                        auto td = cand->env.lookup(*insttype);
     1218                                        if (!td) { continue; }
     1219                                        expr = td->bound.get();
     1220                                }
     1221
     1222                                if (auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
     1223                                        if (base->base == target) {
     1224                                                candidates.push_back( std::move(cand) );
     1225                                                reason.code = NoReason;
     1226                                        }
     1227                                }
     1228                        }
     1229                };
     1230
     1231                try {
     1232                        // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd
     1233                        // Clone is purely for memory management
     1234                        std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
     1235
     1236                        // don't prune here, since it's guaranteed all alternatives will have the same type
     1237                        finder.find( tech1.get(), ResolvMode::withoutPrune() );
     1238                        pick_alternatives(finder.candidates, false);
     1239
     1240                        return;
     1241                } catch(SemanticErrorException & ) {}
     1242
     1243                // Fallback : turn (thread&)X into (thread$&)get_thread(X)
     1244                std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
     1245                // don't prune here, since it's guaranteed all alternatives will have the same type
     1246                finder.find( fallback.get(), ResolvMode::withoutPrune() );
     1247
     1248                pick_alternatives(finder.candidates, true);
     1249
     1250                // Whatever happens here, we have no more fallbacks
     1251        }
     1252
     1253        void Finder::postvisit( const ast::UntypedMemberExpr * memberExpr ) {
     1254                CandidateFinder aggFinder( context, tenv );
     1255                aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
     1256                for ( CandidateRef & agg : aggFinder.candidates ) {
     1257                        // it's okay for the aggregate expression to have reference type -- cast it to the
     1258                        // base type to treat the aggregate as the referenced value
     1259                        Cost addedCost = Cost::zero;
     1260                        agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
     1261
     1262                        // find member of the given type
     1263                        if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
     1264                                addAggMembers(
     1265                                        structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1266                        } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
     1267                                addAggMembers(
     1268                                        unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1269                        } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     1270                                addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
     1271                        }
     1272                }
     1273        }
     1274
     1275        void Finder::postvisit( const ast::MemberExpr * memberExpr ) {
     1276                addCandidate( memberExpr, tenv );
     1277        }
     1278
     1279        void Finder::postvisit( const ast::NameExpr * nameExpr ) {
     1280                std::vector< ast::SymbolTable::IdData > declList;
     1281                if (!selfFinder.otypeKeys.empty()) {
     1282                        auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     1283                        assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
     1284
     1285                        for (auto & otypeKey: selfFinder.otypeKeys) {
     1286                                auto result = symtab.specialLookupId(kind, otypeKey);
     1287                                declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
     1288                        }
     1289                } else {
     1290                        declList = symtab.lookupId( nameExpr->name );
     1291                }
     1292                PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
     1293
     1294                if ( declList.empty() ) return;
     1295
     1296                reason.code = NoMatch;
     1297
     1298                for ( auto & data : declList ) {
     1299                        Cost cost = Cost::zero;
     1300                        ast::Expr * newExpr = data.combine( nameExpr->location, cost );
     1301
     1302                        CandidateRef newCand = std::make_shared<Candidate>(
     1303                                newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     1304                                cost );
     1305
     1306                        if (newCand->expr->env) {
     1307                                newCand->env.add(*newCand->expr->env);
     1308                                auto mutExpr = newCand->expr.get_and_mutate();
     1309                                mutExpr->env  = nullptr;
     1310                                newCand->expr = mutExpr;
     1311                        }
     1312
     1313                        PRINT(
     1314                                std::cerr << "decl is ";
     1315                                ast::print( std::cerr, data.id );
     1316                                std::cerr << std::endl;
     1317                                std::cerr << "newExpr is ";
     1318                                ast::print( std::cerr, newExpr );
     1319                                std::cerr << std::endl;
     1320                        )
     1321                        newCand->expr = ast::mutate_field(
     1322                                newCand->expr.get(), &ast::Expr::result,
     1323                                renameTyVars( newCand->expr->result ) );
     1324                        // add anonymous member interpretations whenever an aggregate value type is seen
     1325                        // as a name expression
     1326                        addAnonConversions( newCand );
     1327                        candidates.emplace_back( std::move( newCand ) );
     1328                }
     1329        }
     1330
     1331        void Finder::postvisit( const ast::VariableExpr * variableExpr ) {
     1332                // not sufficient to just pass `variableExpr` here, type might have changed since
     1333                // creation
     1334                addCandidate(
     1335                        new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
     1336        }
     1337
     1338        void Finder::postvisit( const ast::ConstantExpr * constantExpr ) {
     1339                addCandidate( constantExpr, tenv );
     1340        }
     1341
     1342        void Finder::postvisit( const ast::SizeofExpr * sizeofExpr ) {
     1343                if ( sizeofExpr->type ) {
     1344                        addCandidate(
     1345                                new ast::SizeofExpr{
     1346                                        sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
     1347                                tenv );
     1348                } else {
     1349                        // find all candidates for the argument to sizeof
     1350                        CandidateFinder finder( context, tenv );
     1351                        finder.find( sizeofExpr->expr );
     1352                        // find the lowest-cost candidate, otherwise ambiguous
     1353                        CandidateList winners = findMinCost( finder.candidates );
     1354                        if ( winners.size() != 1 ) {
     1355                                SemanticError(
     1356                                        sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
     1357                        }
     1358                        // return the lowest-cost candidate
     1359                        CandidateRef & choice = winners.front();
     1360                        choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1361                        choice->cost = Cost::zero;
     1362                        addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
     1363                }
     1364        }
     1365
     1366        void Finder::postvisit( const ast::AlignofExpr * alignofExpr ) {
     1367                if ( alignofExpr->type ) {
     1368                        addCandidate(
     1369                                new ast::AlignofExpr{
     1370                                        alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
     1371                                tenv );
     1372                } else {
     1373                        // find all candidates for the argument to alignof
     1374                        CandidateFinder finder( context, tenv );
     1375                        finder.find( alignofExpr->expr );
     1376                        // find the lowest-cost candidate, otherwise ambiguous
     1377                        CandidateList winners = findMinCost( finder.candidates );
     1378                        if ( winners.size() != 1 ) {
     1379                                SemanticError(
     1380                                        alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
     1381                        }
     1382                        // return the lowest-cost candidate
     1383                        CandidateRef & choice = winners.front();
     1384                        choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1385                        choice->cost = Cost::zero;
     1386                        addCandidate(
     1387                                *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
     1388                }
     1389        }
     1390
     1391        void Finder::postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
     1392                const ast::BaseInstType * aggInst;
     1393                if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
     1394                else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
     1395                else return;
     1396
     1397                for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
     1398                        auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
     1399                        addCandidate(
     1400                                new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
     1401                }
     1402        }
     1403
     1404        void Finder::postvisit( const ast::OffsetofExpr * offsetofExpr ) {
     1405                addCandidate( offsetofExpr, tenv );
     1406        }
     1407
     1408        void Finder::postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
     1409                addCandidate( offsetPackExpr, tenv );
     1410        }
     1411
     1412        void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) {
     1413                CandidateFinder finder1( context, tenv );
     1414                finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
     1415                if ( finder1.candidates.empty() ) return;
     1416
     1417                CandidateFinder finder2( context, tenv );
     1418                finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
     1419                if ( finder2.candidates.empty() ) return;
     1420
     1421                reason.code = NoMatch;
     1422
     1423                for ( const CandidateRef & r1 : finder1.candidates ) {
     1424                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1425                                ast::TypeEnvironment env{ r1->env };
     1426                                env.simpleCombine( r2->env );
     1427                                ast::OpenVarSet open{ r1->open };
     1428                                mergeOpenVars( open, r2->open );
     1429                                ast::AssertionSet need;
     1430                                mergeAssertionSet( need, r1->need );
     1431                                mergeAssertionSet( need, r2->need );
     1432
     1433                                addCandidate(
     1434                                        new ast::LogicalExpr{
     1435                                                logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
     1436                                        std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
     1437                        }
     1438                }
     1439        }
     1440
     1441        void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) {
     1442                // candidates for condition
     1443                CandidateFinder finder1( context, tenv );
     1444                finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
     1445                if ( finder1.candidates.empty() ) return;
     1446
     1447                // candidates for true result
     1448                CandidateFinder finder2( context, tenv );
     1449                finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
     1450                if ( finder2.candidates.empty() ) return;
     1451
     1452                // candidates for false result
     1453                CandidateFinder finder3( context, tenv );
     1454                finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
     1455                if ( finder3.candidates.empty() ) return;
     1456
     1457                reason.code = NoMatch;
     1458
     1459                for ( const CandidateRef & r1 : finder1.candidates ) {
     1460                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1461                                for ( const CandidateRef & r3 : finder3.candidates ) {
     1462                                        ast::TypeEnvironment env{ r1->env };
     1463                                        env.simpleCombine( r2->env );
     1464                                        env.simpleCombine( r3->env );
     1465                                        ast::OpenVarSet open{ r1->open };
     1466                                        mergeOpenVars( open, r2->open );
     1467                                        mergeOpenVars( open, r3->open );
     1468                                        ast::AssertionSet need;
     1469                                        mergeAssertionSet( need, r1->need );
     1470                                        mergeAssertionSet( need, r2->need );
     1471                                        mergeAssertionSet( need, r3->need );
     1472                                        ast::AssertionSet have;
     1473
     1474                                        // unify true and false results, then infer parameters to produce new
     1475                                        // candidates
     1476                                        ast::ptr< ast::Type > common;
     1477                                        if (
     1478                                                unify(
     1479                                                        r2->expr->result, r3->expr->result, env, need, have, open, symtab,
     1480                                                        common )
     1481                                        ) {
     1482                                                // generate typed expression
     1483                                                ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
     1484                                                        conditionalExpr->location, r1->expr, r2->expr, r3->expr };
     1485                                                newExpr->result = common ? common : r2->expr->result;
     1486                                                // convert both options to result type
     1487                                                Cost cost = r1->cost + r2->cost + r3->cost;
     1488                                                newExpr->arg2 = computeExpressionConversionCost(
     1489                                                        newExpr->arg2, newExpr->result, symtab, env, cost );
     1490                                                newExpr->arg3 = computeExpressionConversionCost(
     1491                                                        newExpr->arg3, newExpr->result, symtab, env, cost );
     1492                                                // output candidate
     1493                                                CandidateRef newCand = std::make_shared<Candidate>(
     1494                                                        newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
     1495                                                inferParameters( newCand, candidates );
     1496                                        }
     1497                                }
     1498                        }
     1499                }
     1500        }
     1501
     1502        void Finder::postvisit( const ast::CommaExpr * commaExpr ) {
     1503                ast::TypeEnvironment env{ tenv };
     1504                ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
     1505
     1506                CandidateFinder finder2( context, env );
     1507                finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     1508
     1509                for ( const CandidateRef & r2 : finder2.candidates ) {
     1510                        addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
     1511                }
     1512        }
     1513
     1514        void Finder::postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
     1515                addCandidate( ctorExpr, tenv );
     1516        }
     1517
     1518        void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) {
     1519                CandidateFinder finder( context, tenv );
     1520                finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
     1521                for ( CandidateRef & r : finder.candidates ) {
     1522                        addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
     1523                }
     1524        }
     1525
     1526        void Finder::postvisit( const ast::RangeExpr * rangeExpr ) {
     1527                // resolve low and high, accept candidates where low and high types unify
     1528                CandidateFinder finder1( context, tenv );
     1529                finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
     1530                if ( finder1.candidates.empty() ) return;
     1531
     1532                CandidateFinder finder2( context, tenv );
     1533                finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
     1534                if ( finder2.candidates.empty() ) return;
     1535
     1536                reason.code = NoMatch;
     1537
     1538                for ( const CandidateRef & r1 : finder1.candidates ) {
     1539                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1540                                ast::TypeEnvironment env{ r1->env };
     1541                                env.simpleCombine( r2->env );
     1542                                ast::OpenVarSet open{ r1->open };
     1543                                mergeOpenVars( open, r2->open );
     1544                                ast::AssertionSet need;
     1545                                mergeAssertionSet( need, r1->need );
     1546                                mergeAssertionSet( need, r2->need );
     1547                                ast::AssertionSet have;
     1548
     1549                                ast::ptr< ast::Type > common;
     1550                                if (
     1551                                        unify(
     1552                                                r1->expr->result, r2->expr->result, env, need, have, open, symtab,
     1553                                                common )
     1554                                ) {
     1555                                        // generate new expression
     1556                                        ast::RangeExpr * newExpr =
     1557                                                new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
     1558                                        newExpr->result = common ? common : r1->expr->result;
     1559                                        // add candidate
     1560                                        CandidateRef newCand = std::make_shared<Candidate>(
     1561                                                newExpr, std::move( env ), std::move( open ), std::move( need ),
     1562                                                r1->cost + r2->cost );
     1563                                        inferParameters( newCand, candidates );
     1564                                }
     1565                        }
     1566                }
     1567        }
     1568
     1569        void Finder::postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
     1570                std::vector< CandidateFinder > subCandidates =
     1571                        selfFinder.findSubExprs( tupleExpr->exprs );
     1572                std::vector< CandidateList > possibilities;
     1573                combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
     1574
     1575                for ( const CandidateList & subs : possibilities ) {
     1576                        std::vector< ast::ptr< ast::Expr > > exprs;
     1577                        exprs.reserve( subs.size() );
     1578                        for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
     1579
     1580                        ast::TypeEnvironment env;
     1581                        ast::OpenVarSet open;
     1582                        ast::AssertionSet need;
     1583                        for ( const CandidateRef & sub : subs ) {
     1584                                env.simpleCombine( sub->env );
     1585                                mergeOpenVars( open, sub->open );
     1586                                mergeAssertionSet( need, sub->need );
     1587                        }
     1588
     1589                        addCandidate(
     1590                                new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
     1591                                std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
     1592                }
     1593        }
     1594
     1595        void Finder::postvisit( const ast::TupleExpr * tupleExpr ) {
     1596                addCandidate( tupleExpr, tenv );
     1597        }
     1598
     1599        void Finder::postvisit( const ast::TupleIndexExpr * tupleExpr ) {
     1600                addCandidate( tupleExpr, tenv );
     1601        }
     1602
     1603        void Finder::postvisit( const ast::TupleAssignExpr * tupleExpr ) {
     1604                addCandidate( tupleExpr, tenv );
     1605        }
     1606
     1607        void Finder::postvisit( const ast::UniqueExpr * unqExpr ) {
     1608                CandidateFinder finder( context, tenv );
     1609                finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
     1610                for ( CandidateRef & r : finder.candidates ) {
     1611                        // ensure that the the id is passed on so that the expressions are "linked"
     1612                        addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
     1613                }
     1614        }
     1615
     1616        void Finder::postvisit( const ast::StmtExpr * stmtExpr ) {
     1617                addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
     1618        }
     1619
     1620        void Finder::postvisit( const ast::UntypedInitExpr * initExpr ) {
     1621                // handle each option like a cast
     1622                CandidateList matches;
     1623                PRINT(
     1624                        std::cerr << "untyped init expr: " << initExpr << std::endl;
     1625                )
     1626                // O(n^2) checks of d-types with e-types
     1627                for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
     1628                        // calculate target type
     1629                        const ast::Type * toType = resolveTypeof( initAlt.type, context );
     1630                        toType = adjustExprType( toType, tenv, symtab );
     1631                        // The call to find must occur inside this loop, otherwise polymorphic return
     1632                        // types are not bound to the initialization type, since return type variables are
     1633                        // only open for the duration of resolving the UntypedExpr.
     1634                        CandidateFinder finder( context, tenv, toType );
     1635                        finder.find( initExpr->expr, ResolvMode::withAdjustment() );
     1636                        for ( CandidateRef & cand : finder.candidates ) {
     1637                                if (reason.code == NotFound) reason.code = NoMatch;
     1638
     1639                                ast::TypeEnvironment env{ cand->env };
     1640                                ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     1641                                ast::OpenVarSet open{ cand->open };
     1642
     1643                                PRINT(
     1644                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
     1645                                )
     1646
     1647                                // It is possible that a cast can throw away some values in a multiply-valued
     1648                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
     1649                                // the subexpression results that are cast directly. The candidate is invalid
     1650                                // if it has fewer results than there are types to cast to.
     1651                                int discardedValues = cand->expr->result->size() - toType->size();
     1652                                if ( discardedValues < 0 ) continue;
     1653
     1654                                // unification run for side-effects
     1655                                bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
     1656                                (void) canUnify;
     1657                                Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1658                                        symtab, env );
     1659                                PRINT(
     1660                                        Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1661                                                symtab, env );
     1662                                        std::cerr << "Considering initialization:";
     1663                                        std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
     1664                                        std::cerr << std::endl << "  TO: "   << toType             << std::endl;
     1665                                        std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
     1666                                        std::cerr << std::endl << "  Legacy cost " << legacyCost;
     1667                                        std::cerr << std::endl << "  New cost " << thisCost;
     1668                                        std::cerr << std::endl;
     1669                                )
     1670                                if ( thisCost != Cost::infinity ) {
     1671                                        // count one safe conversion for each value that is thrown away
     1672                                        thisCost.incSafe( discardedValues );
     1673                                        CandidateRef newCand = std::make_shared<Candidate>(
     1674                                                new ast::InitExpr{
     1675                                                        initExpr->location, restructureCast( cand->expr, toType ),
     1676                                                        initAlt.designation },
     1677                                                std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
     1678                                        inferParameters( newCand, matches );
     1679                                }
     1680                        }
     1681                }
     1682
     1683                // select first on argument cost, then conversion cost
     1684                CandidateList minArgCost = findMinCost( matches );
     1685                promoteCvtCost( minArgCost );
     1686                candidates = findMinCost( minArgCost );
     1687        }
     1688
     1689        // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
     1690        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1691        /// return type. Skips ambiguous candidates.
     1692
     1693} // anonymous namespace
     1694
     1695bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
     1696        struct PruneStruct {
     1697                CandidateRef candidate;
     1698                bool ambiguous;
     1699
     1700                PruneStruct() = default;
     1701                PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
     1702        };
     1703
     1704        // find lowest-cost candidate for each type
     1705        std::unordered_map< std::string, PruneStruct > selected;
     1706        // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
     1707        std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
     1708        for ( CandidateRef & candidate : candidates ) {
     1709                std::string mangleName;
     1710                {
     1711                        ast::ptr< ast::Type > newType = candidate->expr->result;
     1712                        assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
     1713                        candidate->env.apply( newType );
     1714                        mangleName = Mangle::mangle( newType );
     1715                }
     1716
     1717                auto found = selected.find( mangleName );
     1718                if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
     1719                        PRINT(
     1720                                std::cerr << "cost " << candidate->cost << " loses to "
     1721                                        << found->second.candidate->cost << std::endl;
     1722                        )
     1723                        continue;
     1724                }
     1725
     1726                // xxx - when do satisfyAssertions produce more than 1 result?
     1727                // this should only happen when initial result type contains
     1728                // unbound type parameters, then it should never be pruned by
     1729                // the previous step, since renameTyVars guarantees the mangled name
     1730                // is unique.
     1731                CandidateList satisfied;
     1732                bool needRecomputeKey = false;
     1733                if (candidate->need.empty()) {
     1734                        satisfied.emplace_back(candidate);
     1735                }
     1736                else {
     1737                        satisfyAssertions(candidate, context.symtab, satisfied, errors);
     1738                        needRecomputeKey = true;
     1739                }
     1740
     1741                for (auto & newCand : satisfied) {
     1742                        // recomputes type key, if satisfyAssertions changed it
     1743                        if (needRecomputeKey)
     1744                        {
     1745                                ast::ptr< ast::Type > newType = newCand->expr->result;
     1746                                assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
     1747                                newCand->env.apply( newType );
     1748                                mangleName = Mangle::mangle( newType );
     1749                        }
     1750                        auto found = selected.find( mangleName );
     1751                        if ( found != selected.end() ) {
     1752                                if ( newCand->cost < found->second.candidate->cost ) {
     1753                                        PRINT(
     1754                                                std::cerr << "cost " << newCand->cost << " beats "
     1755                                                        << found->second.candidate->cost << std::endl;
     1756                                        )
     1757
     1758                                        found->second = PruneStruct{ newCand };
     1759                                } else if ( newCand->cost == found->second.candidate->cost ) {
     1760                                        // if one of the candidates contains a deleted identifier, can pick the other,
     1761                                        // since deleted expressions should not be ambiguous if there is another option
     1762                                        // that is at least as good
     1763                                        if ( findDeletedExpr( newCand->expr ) ) {
     1764                                                // do nothing
     1765                                                PRINT( std::cerr << "candidate is deleted" << std::endl; )
     1766                                        } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
     1767                                                PRINT( std::cerr << "current is deleted" << std::endl; )
     1768                                                found->second = PruneStruct{ newCand };
     1769                                        } else {
     1770                                                PRINT( std::cerr << "marking ambiguous" << std::endl; )
     1771                                                found->second.ambiguous = true;
     1772                                        }
     1773                                } else {
     1774                                        // xxx - can satisfyAssertions increase the cost?
     1775                                        PRINT(
     1776                                                std::cerr << "cost " << newCand->cost << " loses to "
     1777                                                        << found->second.candidate->cost << std::endl;
     1778                                        )
     1779                                }
     1780                        } else {
     1781                                selected.emplace_hint( found, mangleName, newCand );
     1782                        }
     1783                }
     1784        }
     1785
     1786        // report unambiguous min-cost candidates
     1787        // CandidateList out;
     1788        for ( auto & target : selected ) {
     1789                if ( target.second.ambiguous ) continue;
     1790
     1791                CandidateRef cand = target.second.candidate;
     1792
     1793                ast::ptr< ast::Type > newResult = cand->expr->result;
     1794                cand->env.applyFree( newResult );
     1795                cand->expr = ast::mutate_field(
     1796                        cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
     1797
     1798                out.emplace_back( cand );
     1799        }
     1800        // if everything is lost in satisfyAssertions, report the error
     1801        return !selected.empty();
     1802}
     1803
     1804void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
     1805        // Find alternatives for expression
     1806        ast::Pass<Finder> finder{ *this };
     1807        expr->accept( finder );
     1808
     1809        if ( mode.failFast && candidates.empty() ) {
     1810                switch(finder.core.reason.code) {
     1811                case Finder::NotFound:
     1812                        { SemanticError( expr, "No alternatives for expression " ); break; }
     1813                case Finder::NoMatch:
     1814                        { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
     1815                case Finder::ArgsToFew:
     1816                case Finder::ArgsToMany:
     1817                case Finder::RetsToFew:
     1818                case Finder::RetsToMany:
     1819                case Finder::NoReason:
     1820                default:
     1821                        { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
     1822                }
     1823        }
     1824
     1825        /*
     1826        if ( mode.satisfyAssns || mode.prune ) {
     1827                // trim candidates to just those where the assertions are satisfiable
     1828                // - necessary pre-requisite to pruning
     1829                CandidateList satisfied;
     1830                std::vector< std::string > errors;
     1831                for ( CandidateRef & candidate : candidates ) {
     1832                        satisfyAssertions( candidate, localSyms, satisfied, errors );
     1833                }
     1834
     1835                // fail early if none such
     1836                if ( mode.failFast && satisfied.empty() ) {
     1837                        std::ostringstream stream;
     1838                        stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1839                        for ( const auto& err : errors ) {
     1840                                stream << err;
     1841                        }
     1842                        SemanticError( expr->location, stream.str() );
     1843                }
     1844
     1845                // reset candidates
     1846                candidates = move( satisfied );
     1847        }
     1848        */
     1849
     1850        if ( mode.prune ) {
     1851                // trim candidates to single best one
     1852                PRINT(
     1853                        std::cerr << "alternatives before prune:" << std::endl;
     1854                        print( std::cerr, candidates );
     1855                )
     1856
     1857                CandidateList pruned;
     1858                std::vector<std::string> errors;
     1859                bool found = pruneCandidates( candidates, pruned, errors );
     1860
     1861                if ( mode.failFast && pruned.empty() ) {
     1862                        std::ostringstream stream;
     1863                        if (found) {
     1864                                CandidateList winners = findMinCost( candidates );
     1865                                stream << "Cannot choose between " << winners.size() << " alternatives for "
     1866                                        "expression\n";
     1867                                ast::print( stream, expr );
     1868                                stream << " Alternatives are:\n";
     1869                                print( stream, winners, 1 );
     1870                                SemanticError( expr->location, stream.str() );
     1871                        }
     1872                        else {
     1873                                stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1874                                for ( const auto& err : errors ) {
     1875                                        stream << err;
     1876                                }
     1877                                SemanticError( expr->location, stream.str() );
     1878                        }
     1879                }
     1880
     1881                auto oldsize = candidates.size();
     1882                candidates = std::move( pruned );
     1883
     1884                PRINT(
     1885                        std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
     1886                )
     1887                PRINT(
     1888                        std::cerr << "there are " << candidates.size() << " alternatives after elimination"
     1889                                << std::endl;
     1890                )
     1891        }
     1892
     1893        // adjust types after pruning so that types substituted by pruneAlternatives are correctly
     1894        // adjusted
     1895        if ( mode.adjust ) {
     1896                for ( CandidateRef & r : candidates ) {
     1897                        r->expr = ast::mutate_field(
     1898                                r->expr.get(), &ast::Expr::result,
     1899                                adjustExprType( r->expr->result, r->env, context.symtab ) );
     1900                }
     1901        }
     1902
     1903        // Central location to handle gcc extension keyword, etc. for all expressions
     1904        for ( CandidateRef & r : candidates ) {
     1905                if ( r->expr->extension != expr->extension ) {
     1906                        r->expr.get_and_mutate()->extension = expr->extension;
     1907                }
     1908        }
     1909}
     1910
     1911std::vector< CandidateFinder > CandidateFinder::findSubExprs(
     1912        const std::vector< ast::ptr< ast::Expr > > & xs
     1913) {
     1914        std::vector< CandidateFinder > out;
     1915
     1916        for ( const auto & x : xs ) {
     1917                out.emplace_back( context, env );
     1918                out.back().find( x, ResolvMode::withAdjustment() );
     1919
     1920                PRINT(
     1921                        std::cerr << "findSubExprs" << std::endl;
     1922                        print( std::cerr, out.back().candidates );
     1923                )
     1924        }
     1925
     1926        return out;
     1927}
     1928
    571929const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) {
    581930        if ( expr->result.as< ast::ReferenceType >() ) {
     
    641936        return expr;
    651937}
    66 
    67 /// Unique identifier for matching expression resolutions to their requesting expression
    68 UniqueId globalResnSlot = 0;
    691938
    701939Cost computeConversionCost(
     
    931962}
    941963
    95 namespace {
    96         /// First index is which argument, second is which alternative, third is which exploded element
    97         using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
    98 
    99         /// Returns a list of alternatives with the minimum cost in the given list
    100         CandidateList findMinCost( const CandidateList & candidates ) {
    101                 CandidateList out;
    102                 Cost minCost = Cost::infinity;
    103                 for ( const CandidateRef & r : candidates ) {
    104                         if ( r->cost < minCost ) {
    105                                 minCost = r->cost;
    106                                 out.clear();
    107                                 out.emplace_back( r );
    108                         } else if ( r->cost == minCost ) {
    109                                 out.emplace_back( r );
    110                         }
    111                 }
    112                 return out;
    113         }
    114 
    115         /// Computes conversion cost for a given expression to a given type
    116         const ast::Expr * computeExpressionConversionCost(
    117                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
    118         ) {
    119                 Cost convCost = computeConversionCost(
    120                                 arg->result, paramType, arg->get_lvalue(), symtab, env );
    121                 outCost += convCost;
    122 
    123                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
    124                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to
    125                 // infer parameters and this does not currently work for the reason stated below
    126                 Cost tmpCost = convCost;
    127                 tmpCost.incPoly( -tmpCost.get_polyCost() );
    128                 if ( tmpCost != Cost::zero ) {
    129                         ast::ptr< ast::Type > newType = paramType;
    130                         env.apply( newType );
    131                         return new ast::CastExpr{ arg, newType };
    132 
    133                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not
    134                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
    135                         // once this is fixed it should be possible to resolve the cast.
    136                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
    137                         // but it shouldn't be because this makes the conversion from DT* to DT* since
    138                         // commontype(zero_t, DT*) is DT*, rather than nothing
    139 
    140                         // CandidateFinder finder{ symtab, env };
    141                         // finder.find( arg, ResolvMode::withAdjustment() );
    142                         // assertf( finder.candidates.size() > 0,
    143                         //      "Somehow castable expression failed to find alternatives." );
    144                         // assertf( finder.candidates.size() == 1,
    145                         //      "Somehow got multiple alternatives for known cast expression." );
    146                         // return finder.candidates.front()->expr;
    147                 }
    148 
    149                 return arg;
    150         }
    151 
    152         /// Computes conversion cost for a given candidate
    153         Cost computeApplicationConversionCost(
    154                 CandidateRef cand, const ast::SymbolTable & symtab
    155         ) {
    156                 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
    157                 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    158                 auto function = pointer->base.strict_as< ast::FunctionType >();
    159 
    160                 Cost convCost = Cost::zero;
    161                 const auto & params = function->params;
    162                 auto param = params.begin();
    163                 auto & args = appExpr->args;
    164 
    165                 for ( unsigned i = 0; i < args.size(); ++i ) {
    166                         const ast::Type * argType = args[i]->result;
    167                         PRINT(
    168                                 std::cerr << "arg expression:" << std::endl;
    169                                 ast::print( std::cerr, args[i], 2 );
    170                                 std::cerr << "--- results are" << std::endl;
    171                                 ast::print( std::cerr, argType, 2 );
    172                         )
    173 
    174                         if ( param == params.end() ) {
    175                                 if ( function->isVarArgs ) {
    176                                         convCost.incUnsafe();
    177                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
    178                                                 << convCost << std::endl; ; )
    179                                         // convert reference-typed expressions into value-typed expressions
    180                                         cand->expr = ast::mutate_field_index(
    181                                                 appExpr, &ast::ApplicationExpr::args, i,
    182                                                 referenceToRvalueConversion( args[i], convCost ) );
    183                                         continue;
    184                                 } else return Cost::infinity;
    185                         }
    186 
    187                         if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {
    188                                 // Default arguments should be free - don't include conversion cost.
    189                                 // Unwrap them here because they are not relevant to the rest of the system
    190                                 cand->expr = ast::mutate_field_index(
    191                                         appExpr, &ast::ApplicationExpr::args, i, def->expr );
    192                                 ++param;
    193                                 continue;
    194                         }
    195 
    196                         // mark conversion cost and also specialization cost of param type
    197                         // const ast::Type * paramType = (*param)->get_type();
    198                         cand->expr = ast::mutate_field_index(
    199                                 appExpr, &ast::ApplicationExpr::args, i,
    200                                 computeExpressionConversionCost(
    201                                         args[i], *param, symtab, cand->env, convCost ) );
    202                         convCost.decSpec( specCost( *param ) );
    203                         ++param;  // can't be in for-loop update because of the continue
    204                 }
    205 
    206                 if ( param != params.end() ) return Cost::infinity;
    207 
    208                 // specialization cost of return types can't be accounted for directly, it disables
    209                 // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    210                 //
    211                 //   forall(otype OS) {
    212                 //     void ?|?(OS&, int);  // with newline
    213                 //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
    214                 //   }
    215 
    216                 // mark type variable and specialization cost of forall clause
    217                 convCost.incVar( function->forall.size() );
    218                 convCost.decSpec( function->assertions.size() );
    219 
    220                 return convCost;
    221         }
    222 
    223         void makeUnifiableVars(
    224                 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
    225                 ast::AssertionSet & need
    226         ) {
    227                 for ( auto & tyvar : type->forall ) {
    228                         unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
    229                 }
    230                 for ( auto & assn : type->assertions ) {
    231                         need[ assn ].isUsed = true;
    232                 }
    233         }
    234 
    235         /// Gets a default value from an initializer, nullptr if not present
    236         const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {
    237                 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {
    238                         if ( auto ce = si->value.as< ast::CastExpr >() ) {
    239                                 return ce->arg.as< ast::ConstantExpr >();
    240                         } else {
    241                                 return si->value.as< ast::ConstantExpr >();
    242                         }
    243                 }
    244                 return nullptr;
    245         }
    246 
    247         /// State to iteratively build a match of parameter expressions to arguments
    248         struct ArgPack {
    249                 std::size_t parent;          ///< Index of parent pack
    250                 ast::ptr< ast::Expr > expr;  ///< The argument stored here
    251                 Cost cost;                   ///< The cost of this argument
    252                 ast::TypeEnvironment env;    ///< Environment for this pack
    253                 ast::AssertionSet need;      ///< Assertions outstanding for this pack
    254                 ast::AssertionSet have;      ///< Assertions found for this pack
    255                 ast::OpenVarSet open;        ///< Open variables for this pack
    256                 unsigned nextArg;            ///< Index of next argument in arguments list
    257                 unsigned tupleStart;         ///< Number of tuples that start at this index
    258                 unsigned nextExpl;           ///< Index of next exploded element
    259                 unsigned explAlt;            ///< Index of alternative for nextExpl > 0
    260 
    261                 ArgPack()
    262                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
    263                   tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    264 
    265                 ArgPack(
    266                         const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    267                         const ast::AssertionSet & have, const ast::OpenVarSet & open )
    268                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    269                   open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    270 
    271                 ArgPack(
    272                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
    273                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
    274                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    275                         unsigned nextExpl = 0, unsigned explAlt = 0 )
    276                 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
    277                   have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    278                   nextExpl( nextExpl ), explAlt( explAlt ) {}
    279 
    280                 ArgPack(
    281                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
    282                         ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    283                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
    284                   need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
    285                   tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    286 
    287                 /// true if this pack is in the middle of an exploded argument
    288                 bool hasExpl() const { return nextExpl > 0; }
    289 
    290                 /// Gets the list of exploded candidates for this pack
    291                 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
    292                         return args[ nextArg-1 ][ explAlt ];
    293                 }
    294 
    295                 /// Ends a tuple expression, consolidating the appropriate args
    296                 void endTuple( const std::vector< ArgPack > & packs ) {
    297                         // add all expressions in tuple to list, summing cost
    298                         std::deque< const ast::Expr * > exprs;
    299                         const ArgPack * pack = this;
    300                         if ( expr ) { exprs.emplace_front( expr ); }
    301                         while ( pack->tupleStart == 0 ) {
    302                                 pack = &packs[pack->parent];
    303                                 exprs.emplace_front( pack->expr );
    304                                 cost += pack->cost;
    305                         }
    306                         // reset pack to appropriate tuple
    307                         std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
    308                         expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
    309                         tupleStart = pack->tupleStart - 1;
    310                         parent = pack->parent;
    311                 }
    312         };
    313 
    314         /// Instantiates an argument to match a parameter, returns false if no matching results left
    315         bool instantiateArgument(
    316                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
    317                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
    318                 unsigned nTuples = 0
    319         ) {
    320                 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
    321                         // paramType is a TupleType -- group args into a TupleExpr
    322                         ++nTuples;
    323                         for ( const ast::Type * type : *tupleType ) {
    324                                 // xxx - dropping initializer changes behaviour from previous, but seems correct
    325                                 // ^^^ need to handle the case where a tuple has a default argument
    326                                 if ( ! instantiateArgument(
    327                                         type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    328                                 nTuples = 0;
    329                         }
    330                         // re-constitute tuples for final generation
    331                         for ( auto i = genStart; i < results.size(); ++i ) {
    332                                 results[i].endTuple( results );
    333                         }
    334                         return true;
    335                 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    336                         // paramType is a ttype, consumes all remaining arguments
    337 
    338                         // completed tuples; will be spliced to end of results to finish
    339                         std::vector< ArgPack > finalResults{};
    340 
    341                         // iterate until all results completed
    342                         std::size_t genEnd;
    343                         ++nTuples;
    344                         do {
    345                                 genEnd = results.size();
    346 
    347                                 // add another argument to results
    348                                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    349                                         unsigned nextArg = results[i].nextArg;
    350 
    351                                         // use next element of exploded tuple if present
    352                                         if ( results[i].hasExpl() ) {
    353                                                 const ExplodedArg & expl = results[i].getExpl( args );
    354 
    355                                                 unsigned nextExpl = results[i].nextExpl + 1;
    356                                                 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    357 
    358                                                 results.emplace_back(
    359                                                         i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    360                                                         copy( results[i].need ), copy( results[i].have ),
    361                                                         copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    362                                                         results[i].explAlt );
    363 
    364                                                 continue;
    365                                         }
    366 
    367                                         // finish result when out of arguments
    368                                         if ( nextArg >= args.size() ) {
    369                                                 ArgPack newResult{
    370                                                         results[i].env, results[i].need, results[i].have, results[i].open };
    371                                                 newResult.nextArg = nextArg;
    372                                                 const ast::Type * argType = nullptr;
    373 
    374                                                 if ( nTuples > 0 || ! results[i].expr ) {
    375                                                         // first iteration or no expression to clone,
    376                                                         // push empty tuple expression
    377                                                         newResult.parent = i;
    378                                                         newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
    379                                                         argType = newResult.expr->result;
    380                                                 } else {
    381                                                         // clone result to collect tuple
    382                                                         newResult.parent = results[i].parent;
    383                                                         newResult.cost = results[i].cost;
    384                                                         newResult.tupleStart = results[i].tupleStart;
    385                                                         newResult.expr = results[i].expr;
    386                                                         argType = newResult.expr->result;
    387 
    388                                                         if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
    389                                                                 // the case where a ttype value is passed directly is special,
    390                                                                 // e.g. for argument forwarding purposes
    391                                                                 // xxx - what if passing multiple arguments, last of which is
    392                                                                 //       ttype?
    393                                                                 // xxx - what would happen if unify was changed so that unifying
    394                                                                 //       tuple
    395                                                                 // types flattened both before unifying lists? then pass in
    396                                                                 // TupleType (ttype) below.
    397                                                                 --newResult.tupleStart;
    398                                                         } else {
    399                                                                 // collapse leftover arguments into tuple
    400                                                                 newResult.endTuple( results );
    401                                                                 argType = newResult.expr->result;
    402                                                         }
    403                                                 }
    404 
    405                                                 // check unification for ttype before adding to final
    406                                                 if (
    407                                                         unify(
    408                                                                 ttype, argType, newResult.env, newResult.need, newResult.have,
    409                                                                 newResult.open, symtab )
    410                                                 ) {
    411                                                         finalResults.emplace_back( std::move( newResult ) );
    412                                                 }
    413 
    414                                                 continue;
    415                                         }
    416 
    417                                         // add each possible next argument
    418                                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    419                                                 const ExplodedArg & expl = args[nextArg][j];
    420 
    421                                                 // fresh copies of parent parameters for this iteration
    422                                                 ast::TypeEnvironment env = results[i].env;
    423                                                 ast::OpenVarSet open = results[i].open;
    424 
    425                                                 env.addActual( expl.env, open );
    426 
    427                                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    428                                                 if ( expl.exprs.empty() ) {
    429                                                         results.emplace_back(
    430                                                                 results[i], std::move( env ), copy( results[i].need ),
    431                                                                 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
    432 
    433                                                         continue;
    434                                                 }
    435 
    436                                                 // add new result
    437                                                 results.emplace_back(
    438                                                         i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
    439                                                         copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
    440                                                         expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    441                                         }
    442                                 }
    443 
    444                                 // reset for next round
    445                                 genStart = genEnd;
    446                                 nTuples = 0;
    447                         } while ( genEnd != results.size() );
    448 
    449                         // splice final results onto results
    450                         for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
    451                                 results.emplace_back( std::move( finalResults[i] ) );
    452                         }
    453                         return ! finalResults.empty();
    454                 }
    455 
    456                 // iterate each current subresult
    457                 std::size_t genEnd = results.size();
    458                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    459                         unsigned nextArg = results[i].nextArg;
    460 
    461                         // use remainder of exploded tuple if present
    462                         if ( results[i].hasExpl() ) {
    463                                 const ExplodedArg & expl = results[i].getExpl( args );
    464                                 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];
    465 
    466                                 ast::TypeEnvironment env = results[i].env;
    467                                 ast::AssertionSet need = results[i].need, have = results[i].have;
    468                                 ast::OpenVarSet open = results[i].open;
    469 
    470                                 const ast::Type * argType = expr->result;
    471 
    472                                 PRINT(
    473                                         std::cerr << "param type is ";
    474                                         ast::print( std::cerr, paramType );
    475                                         std::cerr << std::endl << "arg type is ";
    476                                         ast::print( std::cerr, argType );
    477                                         std::cerr << std::endl;
    478                                 )
    479 
    480                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
    481                                         unsigned nextExpl = results[i].nextExpl + 1;
    482                                         if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    483 
    484                                         results.emplace_back(
    485                                                 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
    486                                                 nTuples, Cost::zero, nextExpl, results[i].explAlt );
    487                                 }
    488 
    489                                 continue;
    490                         }
    491 
    492                         // use default initializers if out of arguments
    493                         if ( nextArg >= args.size() ) {
    494                                 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {
    495                                         ast::TypeEnvironment env = results[i].env;
    496                                         ast::AssertionSet need = results[i].need, have = results[i].have;
    497                                         ast::OpenVarSet open = results[i].open;
    498 
    499                                         if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    500                                                 results.emplace_back(
    501                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
    502                                                         std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
    503                                         }
    504                                 }
    505 
    506                                 continue;
    507                         }
    508 
    509                         // Check each possible next argument
    510                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    511                                 const ExplodedArg & expl = args[nextArg][j];
    512 
    513                                 // fresh copies of parent parameters for this iteration
    514                                 ast::TypeEnvironment env = results[i].env;
    515                                 ast::AssertionSet need = results[i].need, have = results[i].have;
    516                                 ast::OpenVarSet open = results[i].open;
    517 
    518                                 env.addActual( expl.env, open );
    519 
    520                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    521                                 if ( expl.exprs.empty() ) {
    522                                         results.emplace_back(
    523                                                 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    524                                                 nextArg + 1, expl.cost );
    525 
    526                                         continue;
    527                                 }
    528 
    529                                 // consider only first exploded arg
    530                                 const ast::Expr * expr = expl.exprs.front();
    531                                 const ast::Type * argType = expr->result;
    532 
    533                                 PRINT(
    534                                         std::cerr << "param type is ";
    535                                         ast::print( std::cerr, paramType );
    536                                         std::cerr << std::endl << "arg type is ";
    537                                         ast::print( std::cerr, argType );
    538                                         std::cerr << std::endl;
    539                                 )
    540 
    541                                 // attempt to unify types
    542                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
    543                                         // add new result
    544                                         results.emplace_back(
    545                                                 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    546                                                 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    547                                 }
    548                         }
    549                 }
    550 
    551                 // reset for next parameter
    552                 genStart = genEnd;
    553 
    554                 return genEnd != results.size();  // were any new results added?
    555         }
    556 
    557         /// Generate a cast expression from `arg` to `toType`
    558         const ast::Expr * restructureCast(
    559                 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    560         ) {
    561                 if (
    562                         arg->result->size() > 1
    563                         && ! toType->isVoid()
    564                         && ! dynamic_cast< const ast::ReferenceType * >( toType )
    565                 ) {
    566                         // Argument is a tuple and the target type is neither void nor a reference. Cast each
    567                         // member of the tuple to its corresponding target type, producing the tuple of those
    568                         // cast expressions. If there are more components of the tuple than components in the
    569                         // target type, then excess components do not come out in the result expression (but
    570                         // UniqueExpr ensures that the side effects will still be produced)
    571                         if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    572                                 // expressions which may contain side effects require a single unique instance of
    573                                 // the expression
    574                                 arg = new ast::UniqueExpr{ arg->location, arg };
    575                         }
    576                         std::vector< ast::ptr< ast::Expr > > components;
    577                         for ( unsigned i = 0; i < toType->size(); ++i ) {
    578                                 // cast each component
    579                                 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    580                                 components.emplace_back(
    581                                         restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    582                         }
    583                         return new ast::TupleExpr{ arg->location, std::move( components ) };
    584                 } else {
    585                         // handle normally
    586                         return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
    587                 }
    588         }
    589 
    590         /// Gets the name from an untyped member expression (must be NameExpr)
    591         const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
    592                 if ( memberExpr->member.as< ast::ConstantExpr >() ) {
    593                         SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
    594                 }
    595 
    596                 return memberExpr->member.strict_as< ast::NameExpr >()->name;
    597         }
    598 
    599         /// Actually visits expressions to find their candidate interpretations
    600         class Finder final : public ast::WithShortCircuiting {
    601                 const ResolveContext & context;
    602                 const ast::SymbolTable & symtab;
    603         public:
    604                 // static size_t traceId;
    605                 CandidateFinder & selfFinder;
    606                 CandidateList & candidates;
    607                 const ast::TypeEnvironment & tenv;
    608                 ast::ptr< ast::Type > & targetType;
    609 
    610                 enum Errors {
    611                         NotFound,
    612                         NoMatch,
    613                         ArgsToFew,
    614                         ArgsToMany,
    615                         RetsToFew,
    616                         RetsToMany,
    617                         NoReason
    618                 };
    619 
    620                 struct {
    621                         Errors code = NotFound;
    622                 } reason;
    623 
    624                 Finder( CandidateFinder & f )
    625                 : context( f.context ), symtab( context.symtab ), selfFinder( f ),
    626                   candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
    627 
    628                 void previsit( const ast::Node * ) { visit_children = false; }
    629 
    630                 /// Convenience to add candidate to list
    631                 template<typename... Args>
    632                 void addCandidate( Args &&... args ) {
    633                         candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
    634                         reason.code = NoReason;
    635                 }
    636 
    637                 void postvisit( const ast::ApplicationExpr * applicationExpr ) {
    638                         addCandidate( applicationExpr, tenv );
    639                 }
    640 
    641                 /// Set up candidate assertions for inference
    642                 void inferParameters( CandidateRef & newCand, CandidateList & out ) {
    643                         // Set need bindings for any unbound assertions
    644                         UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
    645                         for ( auto & assn : newCand->need ) {
    646                                 // skip already-matched assertions
    647                                 if ( assn.second.resnSlot != 0 ) continue;
    648                                 // assign slot for expression if needed
    649                                 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
    650                                 // fix slot to assertion
    651                                 assn.second.resnSlot = crntResnSlot;
    652                         }
    653                         // pair slot to expression
    654                         if ( crntResnSlot != 0 ) {
    655                                 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );
    656                         }
    657 
    658                         // add to output list; assertion satisfaction will occur later
    659                         out.emplace_back( newCand );
    660                 }
    661 
    662                 /// Completes a function candidate with arguments located
    663                 void validateFunctionCandidate(
    664                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
    665                         CandidateList & out
    666                 ) {
    667                         ast::ApplicationExpr * appExpr =
    668                                 new ast::ApplicationExpr{ func->expr->location, func->expr };
    669                         // sum cost and accumulate arguments
    670                         std::deque< const ast::Expr * > args;
    671                         Cost cost = func->cost;
    672                         const ArgPack * pack = &result;
    673                         while ( pack->expr ) {
    674                                 args.emplace_front( pack->expr );
    675                                 cost += pack->cost;
    676                                 pack = &results[pack->parent];
    677                         }
    678                         std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
    679                         appExpr->args = std::move( vargs );
    680                         // build and validate new candidate
    681                         auto newCand =
    682                                 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    683                         PRINT(
    684                                 std::cerr << "instantiate function success: " << appExpr << std::endl;
    685                                 std::cerr << "need assertions:" << std::endl;
    686                                 ast::print( std::cerr, result.need, 2 );
    687                         )
    688                         inferParameters( newCand, out );
    689                 }
    690 
    691                 /// Builds a list of candidates for a function, storing them in out
    692                 void makeFunctionCandidates(
    693                         const CandidateRef & func, const ast::FunctionType * funcType,
    694                         const ExplodedArgs_new & args, CandidateList & out
    695                 ) {
    696                         ast::OpenVarSet funcOpen;
    697                         ast::AssertionSet funcNeed, funcHave;
    698                         ast::TypeEnvironment funcEnv{ func->env };
    699                         makeUnifiableVars( funcType, funcOpen, funcNeed );
    700                         // add all type variables as open variables now so that those not used in the
    701                         // parameter list are still considered open
    702                         funcEnv.add( funcType->forall );
    703 
    704                         if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
    705                                 // attempt to narrow based on expected target type
    706                                 const ast::Type * returnType = funcType->returns.front();
    707                                 if ( ! unify(
    708                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
    709                                 ) {
    710                                         // unification failed, do not pursue this candidate
    711                                         return;
    712                                 }
    713                         }
    714 
    715                         // iteratively build matches, one parameter at a time
    716                         std::vector< ArgPack > results;
    717                         results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );
    718                         std::size_t genStart = 0;
    719 
    720                         // xxx - how to handle default arg after change to ftype representation?
    721                         if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
    722                                 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
    723                                         // function may have default args only if directly calling by name
    724                                         // must use types on candidate however, due to RenameVars substitution
    725                                         auto nParams = funcType->params.size();
    726 
    727                                         for (size_t i=0; i<nParams; ++i) {
    728                                                 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
    729                                                 if (!instantiateArgument(
    730                                                         funcType->params[i], obj->init, args, results, genStart, symtab)) return;
    731                                         }
    732                                         goto endMatch;
    733                                 }
    734                         }
    735                         for ( const auto & param : funcType->params ) {
    736                                 // Try adding the arguments corresponding to the current parameter to the existing
    737                                 // matches
    738                                 // no default args for indirect calls
    739                                 if ( ! instantiateArgument(
    740                                         param, nullptr, args, results, genStart, symtab ) ) return;
    741                         }
    742 
    743                         endMatch:
    744                         if ( funcType->isVarArgs ) {
    745                                 // append any unused arguments to vararg pack
    746                                 std::size_t genEnd;
    747                                 do {
    748                                         genEnd = results.size();
    749 
    750                                         // iterate results
    751                                         for ( std::size_t i = genStart; i < genEnd; ++i ) {
    752                                                 unsigned nextArg = results[i].nextArg;
    753 
    754                                                 // use remainder of exploded tuple if present
    755                                                 if ( results[i].hasExpl() ) {
    756                                                         const ExplodedArg & expl = results[i].getExpl( args );
    757 
    758                                                         unsigned nextExpl = results[i].nextExpl + 1;
    759                                                         if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    760 
    761                                                         results.emplace_back(
    762                                                                 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    763                                                                 copy( results[i].need ), copy( results[i].have ),
    764                                                                 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,
    765                                                                 results[i].explAlt );
    766 
    767                                                         continue;
    768                                                 }
    769 
    770                                                 // finish result when out of arguments
    771                                                 if ( nextArg >= args.size() ) {
    772                                                         validateFunctionCandidate( func, results[i], results, out );
    773 
    774                                                         continue;
    775                                                 }
    776 
    777                                                 // add each possible next argument
    778                                                 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    779                                                         const ExplodedArg & expl = args[nextArg][j];
    780 
    781                                                         // fresh copies of parent parameters for this iteration
    782                                                         ast::TypeEnvironment env = results[i].env;
    783                                                         ast::OpenVarSet open = results[i].open;
    784 
    785                                                         env.addActual( expl.env, open );
    786 
    787                                                         // skip empty tuple arguments by (nearly) cloning parent into next gen
    788                                                         if ( expl.exprs.empty() ) {
    789                                                                 results.emplace_back(
    790                                                                         results[i], std::move( env ), copy( results[i].need ),
    791                                                                         copy( results[i].have ), std::move( open ), nextArg + 1,
    792                                                                         expl.cost );
    793 
    794                                                                 continue;
    795                                                         }
    796 
    797                                                         // add new result
    798                                                         results.emplace_back(
    799                                                                 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
    800                                                                 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
    801                                                                 expl.exprs.size() == 1 ? 0 : 1, j );
    802                                                 }
    803                                         }
    804 
    805                                         genStart = genEnd;
    806                                 } while( genEnd != results.size() );
    807                         } else {
    808                                 // filter out the results that don't use all the arguments
    809                                 for ( std::size_t i = genStart; i < results.size(); ++i ) {
    810                                         ArgPack & result = results[i];
    811                                         if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
    812                                                 validateFunctionCandidate( func, result, results, out );
    813                                         }
    814                                 }
    815                         }
    816                 }
    817 
    818                 /// Adds implicit struct-conversions to the alternative list
    819                 void addAnonConversions( const CandidateRef & cand ) {
    820                         // adds anonymous member interpretations whenever an aggregate value type is seen.
    821                         // it's okay for the aggregate expression to have reference type -- cast it to the
    822                         // base type to treat the aggregate as the referenced value
    823                         ast::ptr< ast::Expr > aggrExpr( cand->expr );
    824                         ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    825                         cand->env.apply( aggrType );
    826 
    827                         if ( aggrType.as< ast::ReferenceType >() ) {
    828                                 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
    829                         }
    830 
    831                         if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
    832                                 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
    833                         } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    834                                 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
    835                         }
    836                 }
    837 
    838                 /// Adds aggregate member interpretations
    839                 void addAggMembers(
    840                         const ast::BaseInstType * aggrInst, const ast::Expr * expr,
    841                         const Candidate & cand, const Cost & addedCost, const std::string & name
    842                 ) {
    843                         for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    844                                 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    845                                 CandidateRef newCand = std::make_shared<Candidate>(
    846                                         cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    847                                 // add anonymous member interpretations whenever an aggregate value type is seen
    848                                 // as a member expression
    849                                 addAnonConversions( newCand );
    850                                 candidates.emplace_back( std::move( newCand ) );
    851                         }
    852                 }
    853 
    854                 /// Adds tuple member interpretations
    855                 void addTupleMembers(
    856                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
    857                         const Cost & addedCost, const ast::Expr * member
    858                 ) {
    859                         if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    860                                 // get the value of the constant expression as an int, must be between 0 and the
    861                                 // length of the tuple to have meaning
    862                                 long long val = constantExpr->intValue();
    863                                 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    864                                         addCandidate(
    865                                                 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
    866                                                 addedCost );
    867                                 }
    868                         }
    869                 }
    870 
    871                 void postvisit( const ast::UntypedExpr * untypedExpr ) {
    872                         std::vector< CandidateFinder > argCandidates =
    873                                 selfFinder.findSubExprs( untypedExpr->args );
    874 
    875                         // take care of possible tuple assignments
    876                         // if not tuple assignment, handled as normal function call
    877                         Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
    878 
    879                         CandidateFinder funcFinder( context, tenv );
    880                         if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
    881                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    882                                 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    883                                         assertf(!argCandidates.empty(), "special function call without argument");
    884                                         for (auto & firstArgCand: argCandidates[0]) {
    885                                                 ast::ptr<ast::Type> argType = firstArgCand->expr->result;
    886                                                 firstArgCand->env.apply(argType);
    887                                                 // strip references
    888                                                 // xxx - is this correct?
    889                                                 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
    890 
    891                                                 // convert 1-tuple to plain type
    892                                                 if (auto tuple = argType.as<ast::TupleType>()) {
    893                                                         if (tuple->size() == 1) {
    894                                                                 argType = tuple->types[0];
    895                                                         }
    896                                                 }
    897 
    898                                                 // if argType is an unbound type parameter, all special functions need to be searched.
    899                                                 if (isUnboundType(argType)) {
    900                                                         funcFinder.otypeKeys.clear();
    901                                                         break;
    902                                                 }
    903 
    904                                                 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
    905                                                 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
    906                                                 //      const ast::EnumDecl * enumDecl = enumInst->base; // Here
    907                                                 //      if ( const ast::Type* enumType = enumDecl->base ) {
    908                                                 //              // instance of enum (T) is a instance of type (T)
    909                                                 //              funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
    910                                                 //      } else {
    911                                                 //              // instance of an untyped enum is techically int
    912                                                 //              funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
    913                                                 //      }
    914                                                 // }
    915                                                 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
    916                                         }
    917                                 }
    918                         }
    919                         // if candidates are already produced, do not fail
    920                         // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
    921                         // this means there exists ctor/assign functions with a tuple as first parameter.
    922                         ResolvMode mode = {
    923                                 true, // adjust
    924                                 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
    925                                 selfFinder.candidates.empty() // failfast if other options are not found
    926                         };
    927                         funcFinder.find( untypedExpr->func, mode );
    928                         // short-circuit if no candidates
    929                         // if ( funcFinder.candidates.empty() ) return;
    930 
    931                         reason.code = NoMatch;
    932 
    933                         // find function operators
    934                         ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
    935                         CandidateFinder opFinder( context, tenv );
    936                         // okay if there aren't any function operations
    937                         opFinder.find( opExpr, ResolvMode::withoutFailFast() );
    938                         PRINT(
    939                                 std::cerr << "known function ops:" << std::endl;
    940                                 print( std::cerr, opFinder.candidates, 1 );
    941                         )
    942 
    943                         // pre-explode arguments
    944                         ExplodedArgs_new argExpansions;
    945                         for ( const CandidateFinder & args : argCandidates ) {
    946                                 argExpansions.emplace_back();
    947                                 auto & argE = argExpansions.back();
    948                                 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
    949                         }
    950 
    951                         // Find function matches
    952                         CandidateList found;
    953                         SemanticErrorException errors;
    954                         for ( CandidateRef & func : funcFinder ) {
    955                                 try {
    956                                         PRINT(
    957                                                 std::cerr << "working on alternative:" << std::endl;
    958                                                 print( std::cerr, *func, 2 );
    959                                         )
    960 
    961                                         // check if the type is a pointer to function
    962                                         const ast::Type * funcResult = func->expr->result->stripReferences();
    963                                         if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
    964                                                 if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    965                                                         CandidateRef newFunc{ new Candidate{ *func } };
    966                                                         newFunc->expr =
    967                                                                 referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    968                                                         makeFunctionCandidates( newFunc, function, argExpansions, found );
    969                                                 }
    970                                         } else if (
    971                                                 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
    972                                         ) {
    973                                                 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
    974                                                         if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    975                                                                 CandidateRef newFunc{ new Candidate{ *func } };
    976                                                                 newFunc->expr =
    977                                                                         referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    978                                                                 makeFunctionCandidates( newFunc, function, argExpansions, found );
    979                                                         }
    980                                                 }
    981                                         }
    982                                 } catch ( SemanticErrorException & e ) { errors.append( e ); }
    983                         }
    984 
    985                         // Find matches on function operators `?()`
    986                         if ( ! opFinder.candidates.empty() ) {
    987                                 // add exploded function alternatives to front of argument list
    988                                 std::vector< ExplodedArg > funcE;
    989                                 funcE.reserve( funcFinder.candidates.size() );
    990                                 for ( const CandidateRef & func : funcFinder ) {
    991                                         funcE.emplace_back( *func, symtab );
    992                                 }
    993                                 argExpansions.emplace_front( std::move( funcE ) );
    994 
    995                                 for ( const CandidateRef & op : opFinder ) {
    996                                         try {
    997                                                 // check if type is pointer-to-function
    998                                                 const ast::Type * opResult = op->expr->result->stripReferences();
    999                                                 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
    1000                                                         if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    1001                                                                 CandidateRef newOp{ new Candidate{ *op} };
    1002                                                                 newOp->expr =
    1003                                                                         referenceToRvalueConversion( newOp->expr, newOp->cost );
    1004                                                                 makeFunctionCandidates( newOp, function, argExpansions, found );
    1005                                                         }
    1006                                                 }
    1007                                         } catch ( SemanticErrorException & e ) { errors.append( e ); }
    1008                                 }
    1009                         }
    1010 
    1011                         // Implement SFINAE; resolution errors are only errors if there aren't any non-error
    1012                         // candidates
    1013                         if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
    1014 
    1015                         // Compute conversion costs
    1016                         for ( CandidateRef & withFunc : found ) {
    1017                                 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
    1018 
    1019                                 PRINT(
    1020                                         auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
    1021                                         auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    1022                                         auto function = pointer->base.strict_as< ast::FunctionType >();
    1023 
    1024                                         std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    1025                                         std::cerr << "parameters are:" << std::endl;
    1026                                         ast::printAll( std::cerr, function->params, 2 );
    1027                                         std::cerr << "arguments are:" << std::endl;
    1028                                         ast::printAll( std::cerr, appExpr->args, 2 );
    1029                                         std::cerr << "bindings are:" << std::endl;
    1030                                         ast::print( std::cerr, withFunc->env, 2 );
    1031                                         std::cerr << "cost is: " << withFunc->cost << std::endl;
    1032                                         std::cerr << "cost of conversion is:" << cvtCost << std::endl;
    1033                                 )
    1034 
    1035                                 if ( cvtCost != Cost::infinity ) {
    1036                                         withFunc->cvtCost = cvtCost;
    1037                                         candidates.emplace_back( std::move( withFunc ) );
    1038                                 }
    1039                         }
    1040                         found = std::move( candidates );
    1041 
    1042                         // use a new list so that candidates are not examined by addAnonConversions twice
    1043                         CandidateList winners = findMinCost( found );
    1044                         promoteCvtCost( winners );
    1045 
    1046                         // function may return a struct/union value, in which case we need to add candidates
    1047                         // for implicit conversions to each of the anonymous members, which must happen after
    1048                         // `findMinCost`, since anon conversions are never the cheapest
    1049                         for ( const CandidateRef & c : winners ) {
    1050                                 addAnonConversions( c );
    1051                         }
    1052                         spliceBegin( candidates, winners );
    1053 
    1054                         if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    1055                                 // If resolution is unsuccessful with a target type, try again without, since it
    1056                                 // will sometimes succeed when it wouldn't with a target type binding.
    1057                                 // For example:
    1058                                 //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
    1059                                 //   const char * x = "hello world";
    1060                                 //   unsigned char ch = x[0];
    1061                                 // Fails with simple return type binding (xxx -- check this!) as follows:
    1062                                 // * T is bound to unsigned char
    1063                                 // * (x: const char *) is unified with unsigned char *, which fails
    1064                                 // xxx -- fix this better
    1065                                 targetType = nullptr;
    1066                                 postvisit( untypedExpr );
    1067                         }
    1068                 }
    1069 
    1070                 /// true if expression is an lvalue
    1071                 static bool isLvalue( const ast::Expr * x ) {
    1072                         return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
    1073                 }
    1074 
    1075                 void postvisit( const ast::AddressExpr * addressExpr ) {
    1076                         CandidateFinder finder( context, tenv );
    1077                         finder.find( addressExpr->arg );
    1078 
    1079                         if( finder.candidates.empty() ) return;
    1080 
    1081                         reason.code = NoMatch;
    1082 
    1083                         for ( CandidateRef & r : finder.candidates ) {
    1084                                 if ( ! isLvalue( r->expr ) ) continue;
    1085                                 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
    1086                         }
    1087                 }
    1088 
    1089                 void postvisit( const ast::LabelAddressExpr * labelExpr ) {
    1090                         addCandidate( labelExpr, tenv );
    1091                 }
    1092 
    1093                 void postvisit( const ast::CastExpr * castExpr ) {
    1094                         ast::ptr< ast::Type > toType = castExpr->result;
    1095                         assert( toType );
    1096                         toType = resolveTypeof( toType, context );
    1097                         toType = adjustExprType( toType, tenv, symtab );
    1098 
    1099                         CandidateFinder finder( context, tenv, toType );
    1100                         finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    1101 
    1102                         if( !finder.candidates.empty() ) reason.code = NoMatch;
    1103 
    1104                         CandidateList matches;
    1105                         for ( CandidateRef & cand : finder.candidates ) {
    1106                                 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    1107                                 ast::OpenVarSet open( cand->open );
    1108 
    1109                                 cand->env.extractOpenVars( open );
    1110 
    1111                                 // It is possible that a cast can throw away some values in a multiply-valued
    1112                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
    1113                                 // subexpression results that are cast directly. The candidate is invalid if it
    1114                                 // has fewer results than there are types to cast to.
    1115                                 int discardedValues = cand->expr->result->size() - toType->size();
    1116                                 if ( discardedValues < 0 ) continue;
    1117 
    1118                                 // unification run for side-effects
    1119                                 unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1120                                 Cost thisCost =
    1121                                         (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
    1122                             ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
    1123                             : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
    1124 
    1125                                 PRINT(
    1126                                         std::cerr << "working on cast with result: " << toType << std::endl;
    1127                                         std::cerr << "and expr type: " << cand->expr->result << std::endl;
    1128                                         std::cerr << "env: " << cand->env << std::endl;
    1129                                 )
    1130                                 if ( thisCost != Cost::infinity ) {
    1131                                         PRINT(
    1132                                                 std::cerr << "has finite cost." << std::endl;
    1133                                         )
    1134                                         // count one safe conversion for each value that is thrown away
    1135                                         thisCost.incSafe( discardedValues );
    1136                                         CandidateRef newCand = std::make_shared<Candidate>(
    1137                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1138                                                 copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
    1139                                                 cand->cost + thisCost );
    1140                                         inferParameters( newCand, matches );
    1141                                 }
    1142                         }
    1143 
    1144                         // select first on argument cost, then conversion cost
    1145                         CandidateList minArgCost = findMinCost( matches );
    1146                         promoteCvtCost( minArgCost );
    1147                         candidates = findMinCost( minArgCost );
    1148                 }
    1149 
    1150                 void postvisit( const ast::VirtualCastExpr * castExpr ) {
    1151                         assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
    1152                         CandidateFinder finder( context, tenv );
    1153                         // don't prune here, all alternatives guaranteed to have same type
    1154                         finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    1155                         for ( CandidateRef & r : finder.candidates ) {
    1156                                 addCandidate(
    1157                                         *r,
    1158                                         new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    1159                         }
    1160                 }
    1161 
    1162                 void postvisit( const ast::KeywordCastExpr * castExpr ) {
    1163                         const auto & loc = castExpr->location;
    1164                         assertf( castExpr->result, "Cast target should have been set in Validate." );
    1165                         auto ref = castExpr->result.strict_as<ast::ReferenceType>();
    1166                         auto inst = ref->base.strict_as<ast::StructInstType>();
    1167                         auto target = inst->base.get();
    1168 
    1169                         CandidateFinder finder( context, tenv );
    1170 
    1171                         auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
    1172                                 for(auto & cand : found) {
    1173                                         const ast::Type * expr = cand->expr->result.get();
    1174                                         if(expect_ref) {
    1175                                                 auto res = dynamic_cast<const ast::ReferenceType*>(expr);
    1176                                                 if(!res) { continue; }
    1177                                                 expr = res->base.get();
    1178                                         }
    1179 
    1180                                         if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
    1181                                                 auto td = cand->env.lookup(*insttype);
    1182                                                 if(!td) { continue; }
    1183                                                 expr = td->bound.get();
    1184                                         }
    1185 
    1186                                         if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
    1187                                                 if(base->base == target) {
    1188                                                         candidates.push_back( std::move(cand) );
    1189                                                         reason.code = NoReason;
    1190                                                 }
    1191                                         }
    1192                                 }
    1193                         };
    1194 
    1195                         try {
    1196                                 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd
    1197                                 // Clone is purely for memory management
    1198                                 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
    1199 
    1200                                 // don't prune here, since it's guaranteed all alternatives will have the same type
    1201                                 finder.find( tech1.get(), ResolvMode::withoutPrune() );
    1202                                 pick_alternatives(finder.candidates, false);
    1203 
    1204                                 return;
    1205                         } catch(SemanticErrorException & ) {}
    1206 
    1207                         // Fallback : turn (thread&)X into (thread$&)get_thread(X)
    1208                         std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
    1209                         // don't prune here, since it's guaranteed all alternatives will have the same type
    1210                         finder.find( fallback.get(), ResolvMode::withoutPrune() );
    1211 
    1212                         pick_alternatives(finder.candidates, true);
    1213 
    1214                         // Whatever happens here, we have no more fallbacks
    1215                 }
    1216 
    1217                 void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
    1218                         CandidateFinder aggFinder( context, tenv );
    1219                         aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    1220                         for ( CandidateRef & agg : aggFinder.candidates ) {
    1221                                 // it's okay for the aggregate expression to have reference type -- cast it to the
    1222                                 // base type to treat the aggregate as the referenced value
    1223                                 Cost addedCost = Cost::zero;
    1224                                 agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
    1225 
    1226                                 // find member of the given type
    1227                                 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1228                                         addAggMembers(
    1229                                                 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    1230                                 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1231                                         addAggMembers(
    1232                                                 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    1233                                 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
    1234                                         addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
    1235                                 }
    1236                         }
    1237                 }
    1238 
    1239                 void postvisit( const ast::MemberExpr * memberExpr ) {
    1240                         addCandidate( memberExpr, tenv );
    1241                 }
    1242 
    1243                 void postvisit( const ast::NameExpr * nameExpr ) {
    1244                         std::vector< ast::SymbolTable::IdData > declList;
    1245                         if (!selfFinder.otypeKeys.empty()) {
    1246                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    1247                                 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
    1248 
    1249                                 for (auto & otypeKey: selfFinder.otypeKeys) {
    1250                                         auto result = symtab.specialLookupId(kind, otypeKey);
    1251                                         declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
    1252                                 }
    1253                         }
    1254                         else {
    1255                                 declList = symtab.lookupId( nameExpr->name );
    1256                         }
    1257                         PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
    1258 
    1259                         if( declList.empty() ) return;
    1260 
    1261                         reason.code = NoMatch;
    1262 
    1263                         for ( auto & data : declList ) {
    1264                                 Cost cost = Cost::zero;
    1265                                 ast::Expr * newExpr = data.combine( nameExpr->location, cost );
    1266 
    1267                                 CandidateRef newCand = std::make_shared<Candidate>(
    1268                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
    1269                                         cost );
    1270 
    1271                                 if (newCand->expr->env) {
    1272                                         newCand->env.add(*newCand->expr->env);
    1273                                         auto mutExpr = newCand->expr.get_and_mutate();
    1274                                         mutExpr->env  = nullptr;
    1275                                         newCand->expr = mutExpr;
    1276                                 }
    1277 
    1278                                 PRINT(
    1279                                         std::cerr << "decl is ";
    1280                                         ast::print( std::cerr, data.id );
    1281                                         std::cerr << std::endl;
    1282                                         std::cerr << "newExpr is ";
    1283                                         ast::print( std::cerr, newExpr );
    1284                                         std::cerr << std::endl;
    1285                                 )
    1286                                 newCand->expr = ast::mutate_field(
    1287                                         newCand->expr.get(), &ast::Expr::result,
    1288                                         renameTyVars( newCand->expr->result ) );
    1289                                 // add anonymous member interpretations whenever an aggregate value type is seen
    1290                                 // as a name expression
    1291                                 addAnonConversions( newCand );
    1292                                 candidates.emplace_back( std::move( newCand ) );
    1293                         }
    1294                 }
    1295 
    1296                 void postvisit( const ast::VariableExpr * variableExpr ) {
    1297                         // not sufficient to just pass `variableExpr` here, type might have changed since
    1298                         // creation
    1299                         addCandidate(
    1300                                 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    1301                 }
    1302 
    1303                 void postvisit( const ast::ConstantExpr * constantExpr ) {
    1304                         addCandidate( constantExpr, tenv );
    1305                 }
    1306 
    1307                 void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    1308                         if ( sizeofExpr->type ) {
    1309                                 addCandidate(
    1310                                         new ast::SizeofExpr{
    1311                                                 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
    1312                                         tenv );
    1313                         } else {
    1314                                 // find all candidates for the argument to sizeof
    1315                                 CandidateFinder finder( context, tenv );
    1316                                 finder.find( sizeofExpr->expr );
    1317                                 // find the lowest-cost candidate, otherwise ambiguous
    1318                                 CandidateList winners = findMinCost( finder.candidates );
    1319                                 if ( winners.size() != 1 ) {
    1320                                         SemanticError(
    1321                                                 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    1322                                 }
    1323                                 // return the lowest-cost candidate
    1324                                 CandidateRef & choice = winners.front();
    1325                                 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    1326                                 choice->cost = Cost::zero;
    1327                                 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
    1328                         }
    1329                 }
    1330 
    1331                 void postvisit( const ast::AlignofExpr * alignofExpr ) {
    1332                         if ( alignofExpr->type ) {
    1333                                 addCandidate(
    1334                                         new ast::AlignofExpr{
    1335                                                 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
    1336                                         tenv );
    1337                         } else {
    1338                                 // find all candidates for the argument to alignof
    1339                                 CandidateFinder finder( context, tenv );
    1340                                 finder.find( alignofExpr->expr );
    1341                                 // find the lowest-cost candidate, otherwise ambiguous
    1342                                 CandidateList winners = findMinCost( finder.candidates );
    1343                                 if ( winners.size() != 1 ) {
    1344                                         SemanticError(
    1345                                                 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    1346                                 }
    1347                                 // return the lowest-cost candidate
    1348                                 CandidateRef & choice = winners.front();
    1349                                 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    1350                                 choice->cost = Cost::zero;
    1351                                 addCandidate(
    1352                                         *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    1353                         }
    1354                 }
    1355 
    1356                 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
    1357                         const ast::BaseInstType * aggInst;
    1358                         if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
    1359                         else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
    1360                         else return;
    1361 
    1362                         for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    1363                                 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1364                                 addCandidate(
    1365                                         new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    1366                         }
    1367                 }
    1368 
    1369                 void postvisit( const ast::OffsetofExpr * offsetofExpr ) {
    1370                         addCandidate( offsetofExpr, tenv );
    1371                 }
    1372 
    1373                 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
    1374                         addCandidate( offsetPackExpr, tenv );
    1375                 }
    1376 
    1377                 void postvisit( const ast::LogicalExpr * logicalExpr ) {
    1378                         CandidateFinder finder1( context, tenv );
    1379                         finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
    1380                         if ( finder1.candidates.empty() ) return;
    1381 
    1382                         CandidateFinder finder2( context, tenv );
    1383                         finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    1384                         if ( finder2.candidates.empty() ) return;
    1385 
    1386                         reason.code = NoMatch;
    1387 
    1388                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1389                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1390                                         ast::TypeEnvironment env{ r1->env };
    1391                                         env.simpleCombine( r2->env );
    1392                                         ast::OpenVarSet open{ r1->open };
    1393                                         mergeOpenVars( open, r2->open );
    1394                                         ast::AssertionSet need;
    1395                                         mergeAssertionSet( need, r1->need );
    1396                                         mergeAssertionSet( need, r2->need );
    1397 
    1398                                         addCandidate(
    1399                                                 new ast::LogicalExpr{
    1400                                                         logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    1401                                                 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
    1402                                 }
    1403                         }
    1404                 }
    1405 
    1406                 void postvisit( const ast::ConditionalExpr * conditionalExpr ) {
    1407                         // candidates for condition
    1408                         CandidateFinder finder1( context, tenv );
    1409                         finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
    1410                         if ( finder1.candidates.empty() ) return;
    1411 
    1412                         // candidates for true result
    1413                         CandidateFinder finder2( context, tenv );
    1414                         finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
    1415                         if ( finder2.candidates.empty() ) return;
    1416 
    1417                         // candidates for false result
    1418                         CandidateFinder finder3( context, tenv );
    1419                         finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    1420                         if ( finder3.candidates.empty() ) return;
    1421 
    1422                         reason.code = NoMatch;
    1423 
    1424                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1425                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1426                                         for ( const CandidateRef & r3 : finder3.candidates ) {
    1427                                                 ast::TypeEnvironment env{ r1->env };
    1428                                                 env.simpleCombine( r2->env );
    1429                                                 env.simpleCombine( r3->env );
    1430                                                 ast::OpenVarSet open{ r1->open };
    1431                                                 mergeOpenVars( open, r2->open );
    1432                                                 mergeOpenVars( open, r3->open );
    1433                                                 ast::AssertionSet need;
    1434                                                 mergeAssertionSet( need, r1->need );
    1435                                                 mergeAssertionSet( need, r2->need );
    1436                                                 mergeAssertionSet( need, r3->need );
    1437                                                 ast::AssertionSet have;
    1438 
    1439                                                 // unify true and false results, then infer parameters to produce new
    1440                                                 // candidates
    1441                                                 ast::ptr< ast::Type > common;
    1442                                                 if (
    1443                                                         unify(
    1444                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab,
    1445                                                                 common )
    1446                                                 ) {
    1447                                                         // generate typed expression
    1448                                                         ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
    1449                                                                 conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    1450                                                         newExpr->result = common ? common : r2->expr->result;
    1451                                                         // convert both options to result type
    1452                                                         Cost cost = r1->cost + r2->cost + r3->cost;
    1453                                                         newExpr->arg2 = computeExpressionConversionCost(
    1454                                                                 newExpr->arg2, newExpr->result, symtab, env, cost );
    1455                                                         newExpr->arg3 = computeExpressionConversionCost(
    1456                                                                 newExpr->arg3, newExpr->result, symtab, env, cost );
    1457                                                         // output candidate
    1458                                                         CandidateRef newCand = std::make_shared<Candidate>(
    1459                                                                 newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
    1460                                                         inferParameters( newCand, candidates );
    1461                                                 }
    1462                                         }
    1463                                 }
    1464                         }
    1465                 }
    1466 
    1467                 void postvisit( const ast::CommaExpr * commaExpr ) {
    1468                         ast::TypeEnvironment env{ tenv };
    1469                         ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
    1470 
    1471                         CandidateFinder finder2( context, env );
    1472                         finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
    1473 
    1474                         for ( const CandidateRef & r2 : finder2.candidates ) {
    1475                                 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
    1476                         }
    1477                 }
    1478 
    1479                 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
    1480                         addCandidate( ctorExpr, tenv );
    1481                 }
    1482 
    1483                 void postvisit( const ast::ConstructorExpr * ctorExpr ) {
    1484                         CandidateFinder finder( context, tenv );
    1485                         finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
    1486                         for ( CandidateRef & r : finder.candidates ) {
    1487                                 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
    1488                         }
    1489                 }
    1490 
    1491                 void postvisit( const ast::RangeExpr * rangeExpr ) {
    1492                         // resolve low and high, accept candidates where low and high types unify
    1493                         CandidateFinder finder1( context, tenv );
    1494                         finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
    1495                         if ( finder1.candidates.empty() ) return;
    1496 
    1497                         CandidateFinder finder2( context, tenv );
    1498                         finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    1499                         if ( finder2.candidates.empty() ) return;
    1500 
    1501                         reason.code = NoMatch;
    1502 
    1503                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1504                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1505                                         ast::TypeEnvironment env{ r1->env };
    1506                                         env.simpleCombine( r2->env );
    1507                                         ast::OpenVarSet open{ r1->open };
    1508                                         mergeOpenVars( open, r2->open );
    1509                                         ast::AssertionSet need;
    1510                                         mergeAssertionSet( need, r1->need );
    1511                                         mergeAssertionSet( need, r2->need );
    1512                                         ast::AssertionSet have;
    1513 
    1514                                         ast::ptr< ast::Type > common;
    1515                                         if (
    1516                                                 unify(
    1517                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab,
    1518                                                         common )
    1519                                         ) {
    1520                                                 // generate new expression
    1521                                                 ast::RangeExpr * newExpr =
    1522                                                         new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    1523                                                 newExpr->result = common ? common : r1->expr->result;
    1524                                                 // add candidate
    1525                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1526                                                         newExpr, std::move( env ), std::move( open ), std::move( need ),
    1527                                                         r1->cost + r2->cost );
    1528                                                 inferParameters( newCand, candidates );
    1529                                         }
    1530                                 }
    1531                         }
    1532                 }
    1533 
    1534                 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1535                         std::vector< CandidateFinder > subCandidates =
    1536                                 selfFinder.findSubExprs( tupleExpr->exprs );
    1537                         std::vector< CandidateList > possibilities;
    1538                         combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
    1539 
    1540                         for ( const CandidateList & subs : possibilities ) {
    1541                                 std::vector< ast::ptr< ast::Expr > > exprs;
    1542                                 exprs.reserve( subs.size() );
    1543                                 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
    1544 
    1545                                 ast::TypeEnvironment env;
    1546                                 ast::OpenVarSet open;
    1547                                 ast::AssertionSet need;
    1548                                 for ( const CandidateRef & sub : subs ) {
    1549                                         env.simpleCombine( sub->env );
    1550                                         mergeOpenVars( open, sub->open );
    1551                                         mergeAssertionSet( need, sub->need );
    1552                                 }
    1553 
    1554                                 addCandidate(
    1555                                         new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
    1556                                         std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
    1557                         }
    1558                 }
    1559 
    1560                 void postvisit( const ast::TupleExpr * tupleExpr ) {
    1561                         addCandidate( tupleExpr, tenv );
    1562                 }
    1563 
    1564                 void postvisit( const ast::TupleIndexExpr * tupleExpr ) {
    1565                         addCandidate( tupleExpr, tenv );
    1566                 }
    1567 
    1568                 void postvisit( const ast::TupleAssignExpr * tupleExpr ) {
    1569                         addCandidate( tupleExpr, tenv );
    1570                 }
    1571 
    1572                 void postvisit( const ast::UniqueExpr * unqExpr ) {
    1573                         CandidateFinder finder( context, tenv );
    1574                         finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
    1575                         for ( CandidateRef & r : finder.candidates ) {
    1576                                 // ensure that the the id is passed on so that the expressions are "linked"
    1577                                 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
    1578                         }
    1579                 }
    1580 
    1581                 void postvisit( const ast::StmtExpr * stmtExpr ) {
    1582                         addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
    1583                 }
    1584 
    1585                 void postvisit( const ast::UntypedInitExpr * initExpr ) {
    1586                         // handle each option like a cast
    1587                         CandidateList matches;
    1588                         PRINT(
    1589                                 std::cerr << "untyped init expr: " << initExpr << std::endl;
    1590                         )
    1591                         // O(n^2) checks of d-types with e-types
    1592                         for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
    1593                                 // calculate target type
    1594                                 const ast::Type * toType = resolveTypeof( initAlt.type, context );
    1595                                 toType = adjustExprType( toType, tenv, symtab );
    1596                                 // The call to find must occur inside this loop, otherwise polymorphic return
    1597                                 // types are not bound to the initialization type, since return type variables are
    1598                                 // only open for the duration of resolving the UntypedExpr.
    1599                                 CandidateFinder finder( context, tenv, toType );
    1600                                 finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    1601                                 for ( CandidateRef & cand : finder.candidates ) {
    1602                                         if(reason.code == NotFound) reason.code = NoMatch;
    1603 
    1604                                         ast::TypeEnvironment env{ cand->env };
    1605                                         ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    1606                                         ast::OpenVarSet open{ cand->open };
    1607 
    1608                                         PRINT(
    1609                                                 std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    1610                                         )
    1611 
    1612                                         // It is possible that a cast can throw away some values in a multiply-valued
    1613                                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
    1614                                         // the subexpression results that are cast directly. The candidate is invalid
    1615                                         // if it has fewer results than there are types to cast to.
    1616                                         int discardedValues = cand->expr->result->size() - toType->size();
    1617                                         if ( discardedValues < 0 ) continue;
    1618 
    1619                                         // unification run for side-effects
    1620                                         bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
    1621                                         (void) canUnify;
    1622                                         Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1623                                                 symtab, env );
    1624                                         PRINT(
    1625                                                 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1626                                                         symtab, env );
    1627                                                 std::cerr << "Considering initialization:";
    1628                                                 std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
    1629                                                 std::cerr << std::endl << "  TO: "   << toType             << std::endl;
    1630                                                 std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
    1631                                                 std::cerr << std::endl << "  Legacy cost " << legacyCost;
    1632                                                 std::cerr << std::endl << "  New cost " << thisCost;
    1633                                                 std::cerr << std::endl;
    1634                                         )
    1635                                         if ( thisCost != Cost::infinity ) {
    1636                                                 // count one safe conversion for each value that is thrown away
    1637                                                 thisCost.incSafe( discardedValues );
    1638                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1639                                                         new ast::InitExpr{
    1640                                                                 initExpr->location, restructureCast( cand->expr, toType ),
    1641                                                                 initAlt.designation },
    1642                                                         std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
    1643                                                 inferParameters( newCand, matches );
    1644                                         }
    1645                                 }
    1646 
    1647                         }
    1648 
    1649                         // select first on argument cost, then conversion cost
    1650                         CandidateList minArgCost = findMinCost( matches );
    1651                         promoteCvtCost( minArgCost );
    1652                         candidates = findMinCost( minArgCost );
    1653                 }
    1654 
    1655                 void postvisit( const ast::InitExpr * ) {
    1656                         assertf( false, "CandidateFinder should never see a resolved InitExpr." );
    1657                 }
    1658 
    1659                 void postvisit( const ast::DeletedExpr * ) {
    1660                         assertf( false, "CandidateFinder should never see a DeletedExpr." );
    1661                 }
    1662 
    1663                 void postvisit( const ast::GenericExpr * ) {
    1664                         assertf( false, "_Generic is not yet supported." );
    1665                 }
    1666         };
    1667 
    1668         // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
    1669         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    1670         /// return type. Skips ambiguous candidates.
    1671 
    1672 } // anonymous namespace
    1673 
    1674 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
    1675         struct PruneStruct {
    1676                 CandidateRef candidate;
    1677                 bool ambiguous;
    1678 
    1679                 PruneStruct() = default;
    1680                 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
    1681         };
    1682 
    1683         // find lowest-cost candidate for each type
    1684         std::unordered_map< std::string, PruneStruct > selected;
    1685         // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
    1686         std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
    1687         for ( CandidateRef & candidate : candidates ) {
    1688                 std::string mangleName;
    1689                 {
    1690                         ast::ptr< ast::Type > newType = candidate->expr->result;
    1691                         assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
    1692                         candidate->env.apply( newType );
    1693                         mangleName = Mangle::mangle( newType );
    1694                 }
    1695 
    1696                 auto found = selected.find( mangleName );
    1697                 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
    1698                         PRINT(
    1699                                 std::cerr << "cost " << candidate->cost << " loses to "
    1700                                         << found->second.candidate->cost << std::endl;
    1701                         )
    1702                         continue;
    1703                 }
    1704 
    1705                 // xxx - when do satisfyAssertions produce more than 1 result?
    1706                 // this should only happen when initial result type contains
    1707                 // unbound type parameters, then it should never be pruned by
    1708                 // the previous step, since renameTyVars guarantees the mangled name
    1709                 // is unique.
    1710                 CandidateList satisfied;
    1711                 bool needRecomputeKey = false;
    1712                 if (candidate->need.empty()) {
    1713                         satisfied.emplace_back(candidate);
    1714                 }
    1715                 else {
    1716                         satisfyAssertions(candidate, context.symtab, satisfied, errors);
    1717                         needRecomputeKey = true;
    1718                 }
    1719 
    1720                 for (auto & newCand : satisfied) {
    1721                         // recomputes type key, if satisfyAssertions changed it
    1722                         if (needRecomputeKey)
    1723                         {
    1724                                 ast::ptr< ast::Type > newType = newCand->expr->result;
    1725                                 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
    1726                                 newCand->env.apply( newType );
    1727                                 mangleName = Mangle::mangle( newType );
    1728                         }
    1729                         auto found = selected.find( mangleName );
    1730                         if ( found != selected.end() ) {
    1731                                 if ( newCand->cost < found->second.candidate->cost ) {
    1732                                         PRINT(
    1733                                                 std::cerr << "cost " << newCand->cost << " beats "
    1734                                                         << found->second.candidate->cost << std::endl;
    1735                                         )
    1736 
    1737                                         found->second = PruneStruct{ newCand };
    1738                                 } else if ( newCand->cost == found->second.candidate->cost ) {
    1739                                         // if one of the candidates contains a deleted identifier, can pick the other,
    1740                                         // since deleted expressions should not be ambiguous if there is another option
    1741                                         // that is at least as good
    1742                                         if ( findDeletedExpr( newCand->expr ) ) {
    1743                                                 // do nothing
    1744                                                 PRINT( std::cerr << "candidate is deleted" << std::endl; )
    1745                                         } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
    1746                                                 PRINT( std::cerr << "current is deleted" << std::endl; )
    1747                                                 found->second = PruneStruct{ newCand };
    1748                                         } else {
    1749                                                 PRINT( std::cerr << "marking ambiguous" << std::endl; )
    1750                                                 found->second.ambiguous = true;
    1751                                         }
    1752                                 } else {
    1753                                         // xxx - can satisfyAssertions increase the cost?
    1754                                         PRINT(
    1755                                                 std::cerr << "cost " << newCand->cost << " loses to "
    1756                                                         << found->second.candidate->cost << std::endl;
    1757                                         )
    1758                                 }
    1759                         } else {
    1760                                 selected.emplace_hint( found, mangleName, newCand );
    1761                         }
    1762                 }
    1763         }
    1764 
    1765         // report unambiguous min-cost candidates
    1766         // CandidateList out;
    1767         for ( auto & target : selected ) {
    1768                 if ( target.second.ambiguous ) continue;
    1769 
    1770                 CandidateRef cand = target.second.candidate;
    1771 
    1772                 ast::ptr< ast::Type > newResult = cand->expr->result;
    1773                 cand->env.applyFree( newResult );
    1774                 cand->expr = ast::mutate_field(
    1775                         cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
    1776 
    1777                 out.emplace_back( cand );
    1778         }
    1779         // if everything is lost in satisfyAssertions, report the error
    1780         return !selected.empty();
    1781 }
    1782 
    1783 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
    1784         // Find alternatives for expression
    1785         ast::Pass<Finder> finder{ *this };
    1786         expr->accept( finder );
    1787 
    1788         if ( mode.failFast && candidates.empty() ) {
    1789                 switch(finder.core.reason.code) {
    1790                 case Finder::NotFound:
    1791                         { SemanticError( expr, "No alternatives for expression " ); break; }
    1792                 case Finder::NoMatch:
    1793                         { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
    1794                 case Finder::ArgsToFew:
    1795                 case Finder::ArgsToMany:
    1796                 case Finder::RetsToFew:
    1797                 case Finder::RetsToMany:
    1798                 case Finder::NoReason:
    1799                 default:
    1800                         { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
    1801                 }
    1802         }
    1803 
    1804         /*
    1805         if ( mode.satisfyAssns || mode.prune ) {
    1806                 // trim candidates to just those where the assertions are satisfiable
    1807                 // - necessary pre-requisite to pruning
    1808                 CandidateList satisfied;
    1809                 std::vector< std::string > errors;
    1810                 for ( CandidateRef & candidate : candidates ) {
    1811                         satisfyAssertions( candidate, localSyms, satisfied, errors );
    1812                 }
    1813 
    1814                 // fail early if none such
    1815                 if ( mode.failFast && satisfied.empty() ) {
    1816                         std::ostringstream stream;
    1817                         stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1818                         for ( const auto& err : errors ) {
    1819                                 stream << err;
    1820                         }
    1821                         SemanticError( expr->location, stream.str() );
    1822                 }
    1823 
    1824                 // reset candidates
    1825                 candidates = move( satisfied );
    1826         }
    1827         */
    1828 
    1829         if ( mode.prune ) {
    1830                 // trim candidates to single best one
    1831                 PRINT(
    1832                         std::cerr << "alternatives before prune:" << std::endl;
    1833                         print( std::cerr, candidates );
    1834                 )
    1835 
    1836                 CandidateList pruned;
    1837                 std::vector<std::string> errors;
    1838                 bool found = pruneCandidates( candidates, pruned, errors );
    1839 
    1840                 if ( mode.failFast && pruned.empty() ) {
    1841                         std::ostringstream stream;
    1842                         if (found) {
    1843                                 CandidateList winners = findMinCost( candidates );
    1844                                 stream << "Cannot choose between " << winners.size() << " alternatives for "
    1845                                         "expression\n";
    1846                                 ast::print( stream, expr );
    1847                                 stream << " Alternatives are:\n";
    1848                                 print( stream, winners, 1 );
    1849                                 SemanticError( expr->location, stream.str() );
    1850                         }
    1851                         else {
    1852                                 stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1853                                 for ( const auto& err : errors ) {
    1854                                         stream << err;
    1855                                 }
    1856                                 SemanticError( expr->location, stream.str() );
    1857                         }
    1858                 }
    1859 
    1860                 auto oldsize = candidates.size();
    1861                 candidates = std::move( pruned );
    1862 
    1863                 PRINT(
    1864                         std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
    1865                 )
    1866                 PRINT(
    1867                         std::cerr << "there are " << candidates.size() << " alternatives after elimination"
    1868                                 << std::endl;
    1869                 )
    1870         }
    1871 
    1872         // adjust types after pruning so that types substituted by pruneAlternatives are correctly
    1873         // adjusted
    1874         if ( mode.adjust ) {
    1875                 for ( CandidateRef & r : candidates ) {
    1876                         r->expr = ast::mutate_field(
    1877                                 r->expr.get(), &ast::Expr::result,
    1878                                 adjustExprType( r->expr->result, r->env, context.symtab ) );
    1879                 }
    1880         }
    1881 
    1882         // Central location to handle gcc extension keyword, etc. for all expressions
    1883         for ( CandidateRef & r : candidates ) {
    1884                 if ( r->expr->extension != expr->extension ) {
    1885                         r->expr.get_and_mutate()->extension = expr->extension;
    1886                 }
    1887         }
    1888 }
    1889 
    1890 std::vector< CandidateFinder > CandidateFinder::findSubExprs(
    1891         const std::vector< ast::ptr< ast::Expr > > & xs
    1892 ) {
    1893         std::vector< CandidateFinder > out;
    1894 
    1895         for ( const auto & x : xs ) {
    1896                 out.emplace_back( context, env );
    1897                 out.back().find( x, ResolvMode::withAdjustment() );
    1898 
    1899                 PRINT(
    1900                         std::cerr << "findSubExprs" << std::endl;
    1901                         print( std::cerr, out.back().candidates );
    1902                 )
    1903         }
    1904 
    1905         return out;
    1906 }
    1907 
    19081964} // namespace ResolvExpr
    19091965
Note: See TracChangeset for help on using the changeset viewer.