Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/CandidateFinder.cpp

    r0536c03 r18e683b  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1 14:55:00 2019
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed Jun 5 14:30:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    4343#include "SymTab/Validate.h"      // for validateType
    4444#include "Tuples/Tuples.h"        // for handleTupleAssignment
    45 #include "InitTweak/InitTweak.h"  // for getPointerBase
    46 
    47 #include "Common/Stats/Counter.h"
    4845
    4946#define PRINT( text ) if ( resolvep ) { text }
     
    5754                return new ast::CastExpr{ expr, expr->result->stripReferences() };
    5855        }
    59 
     56       
    6057        return expr;
    6158}
     
    6461UniqueId globalResnSlot = 0;
    6562
    66 Cost computeConversionCost(
    67         const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
    68         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     63Cost computeConversionCost( 
     64        const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
     65        const ast::TypeEnvironment & env
    6966) {
    7067        PRINT(
     
    7774                std::cerr << std::endl;
    7875        )
    79         Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env );
     76        Cost convCost = conversionCost( argType, paramType, symtab, env );
    8077        PRINT(
    8178                std::cerr << std::endl << "cost is " << convCost << std::endl;
     
    110107
    111108        /// Computes conversion cost for a given expression to a given type
    112         const ast::Expr * computeExpressionConversionCost(
    113                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
     109        const ast::Expr * computeExpressionConversionCost( 
     110                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 
    114111        ) {
    115                 Cost convCost = computeConversionCost(
    116                                 arg->result, paramType, arg->get_lvalue(), symtab, env );
     112                Cost convCost = computeConversionCost( arg->result, paramType, symtab, env );
    117113                outCost += convCost;
    118114
    119                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
    120                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to
     115                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 
     116                // conversion. Ignore poly cost for now, since this requires resolution of the cast to 
    121117                // infer parameters and this does not currently work for the reason stated below
    122118                Cost tmpCost = convCost;
     
    127123                        return new ast::CastExpr{ arg, newType };
    128124
    129                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not
    130                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
     125                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not 
     126                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 
    131127                        // once this is fixed it should be possible to resolve the cast.
    132                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
    133                         // but it shouldn't be because this makes the conversion from DT* to DT* since
     128                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 
     129                        // but it shouldn't be because this makes the conversion from DT* to DT* since 
    134130                        // commontype(zero_t, DT*) is DT*, rather than nothing
    135131
    136132                        // CandidateFinder finder{ symtab, env };
    137133                        // finder.find( arg, ResolvMode::withAdjustment() );
    138                         // assertf( finder.candidates.size() > 0,
     134                        // assertf( finder.candidates.size() > 0, 
    139135                        //      "Somehow castable expression failed to find alternatives." );
    140                         // assertf( finder.candidates.size() == 1,
     136                        // assertf( finder.candidates.size() == 1, 
    141137                        //      "Somehow got multiple alternatives for known cast expression." );
    142138                        // return finder.candidates.front()->expr;
     
    147143
    148144        /// Computes conversion cost for a given candidate
    149         Cost computeApplicationConversionCost(
    150                 CandidateRef cand, const ast::SymbolTable & symtab
     145        Cost computeApplicationConversionCost( 
     146                CandidateRef cand, const ast::SymbolTable & symtab 
    151147        ) {
    152148                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     
    171167                                if ( function->isVarArgs ) {
    172168                                        convCost.incUnsafe();
    173                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
     169                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 
    174170                                                << convCost << std::endl; ; )
    175171                                        // convert reference-typed expressions into value-typed expressions
    176                                         cand->expr = ast::mutate_field_index(
    177                                                 appExpr, &ast::ApplicationExpr::args, i,
     172                                        cand->expr = ast::mutate_field_index( 
     173                                                appExpr, &ast::ApplicationExpr::args, i, 
    178174                                                referenceToRvalueConversion( args[i], convCost ) );
    179175                                        continue;
     
    184180                                // Default arguments should be free - don't include conversion cost.
    185181                                // Unwrap them here because they are not relevant to the rest of the system
    186                                 cand->expr = ast::mutate_field_index(
     182                                cand->expr = ast::mutate_field_index( 
    187183                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
    188184                                ++param;
     
    191187
    192188                        // mark conversion cost and also specialization cost of param type
    193                         // const ast::Type * paramType = (*param)->get_type();
    194                         cand->expr = ast::mutate_field_index(
    195                                 appExpr, &ast::ApplicationExpr::args, i,
    196                                 computeExpressionConversionCost(
    197                                         args[i], *param, symtab, cand->env, convCost ) );
    198                         convCost.decSpec( specCost( *param ) );
     189                        const ast::Type * paramType = (*param)->get_type();
     190                        cand->expr = ast::mutate_field_index( 
     191                                appExpr, &ast::ApplicationExpr::args, i, 
     192                                computeExpressionConversionCost( 
     193                                        args[i], paramType, symtab, cand->env, convCost ) );
     194                        convCost.decSpec( specCost( paramType ) );
    199195                        ++param;  // can't be in for-loop update because of the continue
    200196                }
     
    202198                if ( param != params.end() ) return Cost::infinity;
    203199
    204                 // specialization cost of return types can't be accounted for directly, it disables
     200                // specialization cost of return types can't be accounted for directly, it disables 
    205201                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    206202                //
     
    212208                // mark type variable and specialization cost of forall clause
    213209                convCost.incVar( function->forall.size() );
    214                 convCost.decSpec( function->assertions.size() );
     210                for ( const ast::TypeDecl * td : function->forall ) {
     211                        convCost.decSpec( td->assertions.size() );
     212                }
    215213
    216214                return convCost;
    217215        }
    218216
    219         void makeUnifiableVars(
    220                 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
    221                 ast::AssertionSet & need
     217        void makeUnifiableVars( 
     218                const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
     219                ast::AssertionSet & need 
    222220        ) {
    223                 for ( auto & tyvar : type->forall ) {
    224                         unifiableVars[ *tyvar ] = ast::TypeDecl::Data{ tyvar->base };
    225                 }
    226                 for ( auto & assn : type->assertions ) {
    227                         need[ assn ].isUsed = true;
     221                for ( const ast::TypeDecl * tyvar : type->forall ) {
     222                        unifiableVars[ tyvar->name ] = ast::TypeDecl::Data{ tyvar };
     223                        for ( const ast::DeclWithType * assn : tyvar->assertions ) {
     224                                need[ assn ].isUsed = true;
     225                        }
    228226                }
    229227        }
     
    256254
    257255                ArgPack()
    258                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
     256                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 
    259257                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    260 
     258               
     259                ArgPack(
     260                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
     261                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
     262                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
     263                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     264               
    261265                ArgPack(
    262                         const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    263                         const ast::AssertionSet & have, const ast::OpenVarSet & open )
    264                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    265                   open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    266 
    267                 ArgPack(
    268                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
    269                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
    270                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
     266                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     267                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     268                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    271269                        unsigned nextExpl = 0, unsigned explAlt = 0 )
    272270                : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ),
    273271                  have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    274272                  nextExpl( nextExpl ), explAlt( explAlt ) {}
    275 
     273               
    276274                ArgPack(
    277                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
     275                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 
    278276                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    279                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),
    280                   need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ),
     277                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 
     278                  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 
    281279                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    282 
     280               
    283281                /// true if this pack is in the middle of an exploded argument
    284282                bool hasExpl() const { return nextExpl > 0; }
     
    288286                        return args[ nextArg-1 ][ explAlt ];
    289287                }
    290 
     288               
    291289                /// Ends a tuple expression, consolidating the appropriate args
    292290                void endTuple( const std::vector< ArgPack > & packs ) {
     
    309307
    310308        /// Instantiates an argument to match a parameter, returns false if no matching results left
    311         bool instantiateArgument(
    312                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
    313                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
    314                 unsigned nTuples = 0
     309        bool instantiateArgument( 
     310                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 
     311                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 
     312                unsigned nTuples = 0 
    315313        ) {
    316314                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     
    320318                                // xxx - dropping initializer changes behaviour from previous, but seems correct
    321319                                // ^^^ need to handle the case where a tuple has a default argument
    322                                 if ( ! instantiateArgument(
     320                                if ( ! instantiateArgument( 
    323321                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    324322                                nTuples = 0;
     
    331329                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    332330                        // paramType is a ttype, consumes all remaining arguments
    333 
     331                       
    334332                        // completed tuples; will be spliced to end of results to finish
    335333                        std::vector< ArgPack > finalResults{};
     
    344342                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
    345343                                        unsigned nextArg = results[i].nextArg;
    346 
     344                                       
    347345                                        // use next element of exploded tuple if present
    348346                                        if ( results[i].hasExpl() ) {
     
    354352                                                results.emplace_back(
    355353                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    356                                                         copy( results[i].need ), copy( results[i].have ),
     354                                                        copy( results[i].need ), copy( results[i].have ), 
    357355                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    358356                                                        results[i].explAlt );
     
    372370                                                        // push empty tuple expression
    373371                                                        newResult.parent = i;
    374                                                         newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
     372                                                        std::vector< ast::ptr< ast::Expr > > emptyList;
     373                                                        newResult.expr =
     374                                                                new ast::TupleExpr{ CodeLocation{}, move( emptyList ) };
    375375                                                        argType = newResult.expr->result;
    376376                                                } else {
     
    400400
    401401                                                // check unification for ttype before adding to final
    402                                                 if (
    403                                                         unify(
     402                                                if ( 
     403                                                        unify( 
    404404                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
    405                                                                 newResult.open, symtab )
     405                                                                newResult.open, symtab ) 
    406406                                                ) {
    407407                                                        finalResults.emplace_back( move( newResult ) );
     
    424424                                                if ( expl.exprs.empty() ) {
    425425                                                        results.emplace_back(
    426                                                                 results[i], move( env ), copy( results[i].need ),
     426                                                                results[i], move( env ), copy( results[i].need ), 
    427427                                                                copy( results[i].have ), move( open ), nextArg + 1, expl.cost );
    428 
     428                                                       
    429429                                                        continue;
    430430                                                }
     
    432432                                                // add new result
    433433                                                results.emplace_back(
    434                                                         i, expl.exprs.front(), move( env ), copy( results[i].need ),
    435                                                         copy( results[i].have ), move( open ), nextArg + 1, nTuples,
     434                                                        i, expl.exprs.front(), move( env ), copy( results[i].need ), 
     435                                                        copy( results[i].have ), move( open ), nextArg + 1, nTuples, 
    436436                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    437437                                        }
     
    479479
    480480                                        results.emplace_back(
    481                                                 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg,
     481                                                i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 
    482482                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
    483483                                }
     
    495495                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    496496                                                results.emplace_back(
    497                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),
     497                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 
    498498                                                        move( need ), move( have ), move( open ), nextArg, nTuples );
    499499                                        }
     
    517517                                if ( expl.exprs.empty() ) {
    518518                                        results.emplace_back(
    519                                                 results[i], move( env ), move( need ), move( have ), move( open ),
     519                                                results[i], move( env ), move( need ), move( have ), move( open ), 
    520520                                                nextArg + 1, expl.cost );
    521 
     521                                       
    522522                                        continue;
    523523                                }
     
    539539                                        // add new result
    540540                                        results.emplace_back(
    541                                                 i, expr, move( env ), move( need ), move( have ), move( open ),
     541                                                i, expr, move( env ), move( need ), move( have ), move( open ), 
    542542                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    543543                                }
     
    548548                genStart = genEnd;
    549549
    550                 return genEnd != results.size();  // were any new results added?
     550                return genEnd != results.size();
    551551        }
    552552
    553553        /// Generate a cast expression from `arg` to `toType`
    554         const ast::Expr * restructureCast(
     554        const ast::Expr * restructureCast( 
    555555                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    556556        ) {
    557                 if (
    558                         arg->result->size() > 1
    559                         && ! toType->isVoid()
    560                         && ! dynamic_cast< const ast::ReferenceType * >( toType )
     557                if ( 
     558                        arg->result->size() > 1 
     559                        && ! toType->isVoid() 
     560                        && ! dynamic_cast< const ast::ReferenceType * >( toType ) 
    561561                ) {
    562                         // Argument is a tuple and the target type is neither void nor a reference. Cast each
    563                         // member of the tuple to its corresponding target type, producing the tuple of those
    564                         // cast expressions. If there are more components of the tuple than components in the
    565                         // target type, then excess components do not come out in the result expression (but
     562                        // Argument is a tuple and the target type is neither void nor a reference. Cast each 
     563                        // member of the tuple to its corresponding target type, producing the tuple of those 
     564                        // cast expressions. If there are more components of the tuple than components in the 
     565                        // target type, then excess components do not come out in the result expression (but 
    566566                        // UniqueExpr ensures that the side effects will still be produced)
    567567                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    568                                 // expressions which may contain side effects require a single unique instance of
     568                                // expressions which may contain side effects require a single unique instance of 
    569569                                // the expression
    570570                                arg = new ast::UniqueExpr{ arg->location, arg };
     
    574574                                // cast each component
    575575                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    576                                 components.emplace_back(
     576                                components.emplace_back( 
    577577                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    578578                        }
     
    594594
    595595        /// Actually visits expressions to find their candidate interpretations
    596         class Finder final : public ast::WithShortCircuiting {
     596        struct Finder final : public ast::WithShortCircuiting {
     597                CandidateFinder & selfFinder;
    597598                const ast::SymbolTable & symtab;
    598         public:
    599                 static size_t traceId;
    600                 CandidateFinder & selfFinder;
    601599                CandidateList & candidates;
    602600                const ast::TypeEnvironment & tenv;
    603601                ast::ptr< ast::Type > & targetType;
    604602
    605                 enum Errors {
    606                         NotFound,
    607                         NoMatch,
    608                         ArgsToFew,
    609                         ArgsToMany,
    610                         RetsToFew,
    611                         RetsToMany,
    612                         NoReason
    613                 };
    614 
    615                 struct {
    616                         Errors code = NotFound;
    617                 } reason;
    618 
    619603                Finder( CandidateFinder & f )
    620                 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),
     604                : selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),
    621605                  targetType( f.targetType ) {}
    622 
     606               
    623607                void previsit( const ast::Node * ) { visit_children = false; }
    624608
     
    627611                void addCandidate( Args &&... args ) {
    628612                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
    629                         reason.code = NoReason;
    630613                }
    631614
     
    656639
    657640                /// Completes a function candidate with arguments located
    658                 void validateFunctionCandidate(
    659                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
    660                         CandidateList & out
     641                void validateFunctionCandidate( 
     642                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 
     643                        CandidateList & out 
    661644                ) {
    662                         ast::ApplicationExpr * appExpr =
     645                        ast::ApplicationExpr * appExpr = 
    663646                                new ast::ApplicationExpr{ func->expr->location, func->expr };
    664647                        // sum cost and accumulate arguments
     
    674657                        appExpr->args = move( vargs );
    675658                        // build and validate new candidate
    676                         auto newCand =
     659                        auto newCand = 
    677660                                std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    678661                        PRINT(
     
    686669                /// Builds a list of candidates for a function, storing them in out
    687670                void makeFunctionCandidates(
    688                         const CandidateRef & func, const ast::FunctionType * funcType,
     671                        const CandidateRef & func, const ast::FunctionType * funcType, 
    689672                        const ExplodedArgs_new & args, CandidateList & out
    690673                ) {
     
    693676                        ast::TypeEnvironment funcEnv{ func->env };
    694677                        makeUnifiableVars( funcType, funcOpen, funcNeed );
    695                         // add all type variables as open variables now so that those not used in the
    696                         // parameter list are still considered open
     678                        // add all type variables as open variables now so that those not used in the parameter
     679                        // list are still considered open
    697680                        funcEnv.add( funcType->forall );
    698681
    699682                        if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
    700683                                // attempt to narrow based on expected target type
    701                                 const ast::Type * returnType = funcType->returns.front();
    702                                 if ( ! unify(
    703                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     684                                const ast::Type * returnType = funcType->returns.front()->get_type();
     685                                if ( ! unify( 
     686                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 
    704687                                ) {
    705688                                        // unification failed, do not pursue this candidate
     
    713696                        std::size_t genStart = 0;
    714697
    715                         // xxx - how to handle default arg after change to ftype representation?
    716                         if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
    717                                 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
    718                                         // function may have default args only if directly calling by name
    719                                         // must use types on candidate however, due to RenameVars substitution
    720                                         auto nParams = funcType->params.size();
    721 
    722                                         for (size_t i=0; i<nParams; ++i) {
    723                                                 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
    724                                                 if (!instantiateArgument(
    725                                                         funcType->params[i], obj->init, args, results, genStart, symtab)) return;
    726                                         }
    727                                         goto endMatch;
    728                                 }
    729                         }
    730                         for ( const auto & param : funcType->params ) {
    731                                 // Try adding the arguments corresponding to the current parameter to the existing
     698                        for ( const ast::DeclWithType * param : funcType->params ) {
     699                                auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param );
     700                                // Try adding the arguments corresponding to the current parameter to the existing
    732701                                // matches
    733                                 // no default args for indirect calls
    734                                 if ( ! instantiateArgument(
    735                                         param, nullptr, args, results, genStart, symtab ) ) return;
    736                         }
    737 
    738                         endMatch:
     702                                if ( ! instantiateArgument(
     703                                        obj->type, obj->init, args, results, genStart, symtab ) ) return;
     704                        }
     705
    739706                        if ( funcType->isVarArgs ) {
    740707                                // append any unused arguments to vararg pack
     
    783750                                                        if ( expl.exprs.empty() ) {
    784751                                                                results.emplace_back(
    785                                                                         results[i], move( env ), copy( results[i].need ),
    786                                                                         copy( results[i].have ), move( open ), nextArg + 1,
     752                                                                        results[i], move( env ), copy( results[i].need ), 
     753                                                                        copy( results[i].have ), move( open ), nextArg + 1, 
    787754                                                                        expl.cost );
    788755
     
    793760                                                        results.emplace_back(
    794761                                                                i, expl.exprs.front(), move( env ), copy( results[i].need ),
    795                                                                 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost,
     762                                                                copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 
    796763                                                                expl.exprs.size() == 1 ? 0 : 1, j );
    797764                                                }
     
    813780                /// Adds implicit struct-conversions to the alternative list
    814781                void addAnonConversions( const CandidateRef & cand ) {
    815                         // adds anonymous member interpretations whenever an aggregate value type is seen.
    816                         // it's okay for the aggregate expression to have reference type -- cast it to the
     782                        // adds anonymous member interpretations whenever an aggregate value type is seen. 
     783                        // it's okay for the aggregate expression to have reference type -- cast it to the 
    817784                        // base type to treat the aggregate as the referenced value
    818785                        ast::ptr< ast::Expr > aggrExpr( cand->expr );
    819786                        ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    820787                        cand->env.apply( aggrType );
    821 
     788                       
    822789                        if ( aggrType.as< ast::ReferenceType >() ) {
    823790                                aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     
    832799
    833800                /// Adds aggregate member interpretations
    834                 void addAggMembers(
    835                         const ast::BaseInstType * aggrInst, const ast::Expr * expr,
    836                         const Candidate & cand, const Cost & addedCost, const std::string & name
     801                void addAggMembers( 
     802                        const ast::ReferenceToType * aggrInst, const ast::Expr * expr,
     803                        const Candidate & cand, const Cost & addedCost, const std::string & name 
    837804                ) {
    838805                        for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    839806                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    840                                 CandidateRef newCand = std::make_shared<Candidate>(
     807                                CandidateRef newCand = std::make_shared<Candidate>( 
    841808                                        cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    842                                 // add anonymous member interpretations whenever an aggregate value type is seen
     809                                // add anonymous member interpretations whenever an aggregate value type is seen 
    843810                                // as a member expression
    844811                                addAnonConversions( newCand );
     
    848815
    849816                /// Adds tuple member interpretations
    850                 void addTupleMembers(
    851                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
    852                         const Cost & addedCost, const ast::Expr * member
     817                void addTupleMembers( 
     818                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 
     819                        const Cost & addedCost, const ast::Expr * member 
    853820                ) {
    854821                        if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    855                                 // get the value of the constant expression as an int, must be between 0 and the
     822                                // get the value of the constant expression as an int, must be between 0 and the 
    856823                                // length of the tuple to have meaning
    857824                                long long val = constantExpr->intValue();
    858825                                if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    859826                                        addCandidate(
    860                                                 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
     827                                                cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 
    861828                                                addedCost );
    862829                                }
     
    865832
    866833                void postvisit( const ast::UntypedExpr * untypedExpr ) {
    867                         std::vector< CandidateFinder > argCandidates =
     834                        CandidateFinder funcFinder{ symtab, tenv };
     835                        funcFinder.find( untypedExpr->func, ResolvMode::withAdjustment() );
     836                        // short-circuit if no candidates
     837                        if ( funcFinder.candidates.empty() ) return;
     838
     839                        std::vector< CandidateFinder > argCandidates =
    868840                                selfFinder.findSubExprs( untypedExpr->args );
    869 
     841                       
    870842                        // take care of possible tuple assignments
    871843                        // if not tuple assignment, handled as normal function call
    872844                        Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
    873 
    874                         CandidateFinder funcFinder{ symtab, tenv };
    875                         if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
    876                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    877                                 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    878                                         assertf(!argCandidates.empty(), "special function call without argument");
    879                                         for (auto & firstArgCand: argCandidates[0]) {
    880                                                 ast::ptr<ast::Type> argType = firstArgCand->expr->result;
    881                                                 firstArgCand->env.apply(argType);
    882                                                 // strip references
    883                                                 // xxx - is this correct?
    884                                                 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
    885 
    886                                                 // convert 1-tuple to plain type
    887                                                 if (auto tuple = argType.as<ast::TupleType>()) {
    888                                                         if (tuple->size() == 1) {
    889                                                                 argType = tuple->types[0];
    890                                                         }
    891                                                 }
    892                                                
    893                                                 // if argType is an unbound type parameter, all special functions need to be searched.
    894                                                 if (isUnboundType(argType)) {
    895                                                         funcFinder.otypeKeys.clear();
    896                                                         break;
    897                                                 }
    898 
    899                                                 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);
    900                                                 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
    901                                         }
    902                                 }
    903                         }
    904                         // if candidates are already produced, do not fail
    905                         // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
    906                         // this means there exists ctor/assign functions with a tuple as first parameter.
    907                         ResolvMode mode = {
    908                                 true, // adjust
    909                                 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
    910                                 selfFinder.candidates.empty() // failfast if other options are not found
    911                         };
    912                         funcFinder.find( untypedExpr->func, mode );
    913                         // short-circuit if no candidates
    914                         // if ( funcFinder.candidates.empty() ) return;
    915 
    916                         reason.code = NoMatch;
    917845
    918846                        // find function operators
     
    949877                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    950878                                                        CandidateRef newFunc{ new Candidate{ *func } };
    951                                                         newFunc->expr =
     879                                                        newFunc->expr = 
    952880                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    953881                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
    954882                                                }
    955                                         } else if (
    956                                                 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     883                                        } else if ( 
     884                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 
    957885                                        ) {
    958                                                 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
     886                                                if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
    959887                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    960888                                                                CandidateRef newFunc{ new Candidate{ *func } };
    961                                                                 newFunc->expr =
     889                                                                newFunc->expr = 
    962890                                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    963891                                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     
    973901                                std::vector< ExplodedArg > funcE;
    974902                                funcE.reserve( funcFinder.candidates.size() );
    975                                 for ( const CandidateRef & func : funcFinder ) {
     903                                for ( const CandidateRef & func : funcFinder ) { 
    976904                                        funcE.emplace_back( *func, symtab );
    977905                                }
     
    985913                                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    986914                                                                CandidateRef newOp{ new Candidate{ *op} };
    987                                                                 newOp->expr =
     915                                                                newOp->expr = 
    988916                                                                        referenceToRvalueConversion( newOp->expr, newOp->cost );
    989917                                                                makeFunctionCandidates( newOp, function, argExpansions, found );
     
    994922                        }
    995923
    996                         // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     924                        // Implement SFINAE; resolution errors are only errors if there aren't any non-error 
    997925                        // candidates
    998926                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     
    1006934                                        auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    1007935                                        auto function = pointer->base.strict_as< ast::FunctionType >();
    1008 
     936                                       
    1009937                                        std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    1010938                                        std::cerr << "parameters are:" << std::endl;
     
    1029957                        promoteCvtCost( winners );
    1030958
    1031                         // function may return a struct/union value, in which case we need to add candidates
    1032                         // for implicit conversions to each of the anonymous members, which must happen after
     959                        // function may return a struct/union value, in which case we need to add candidates 
     960                        // for implicit conversions to each of the anonymous members, which must happen after 
    1033961                        // `findMinCost`, since anon conversions are never the cheapest
    1034962                        for ( const CandidateRef & c : winners ) {
     
    1038966
    1039967                        if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    1040                                 // If resolution is unsuccessful with a target type, try again without, since it
     968                                // If resolution is unsuccessful with a target type, try again without, since it 
    1041969                                // will sometimes succeed when it wouldn't with a target type binding.
    1042970                                // For example:
     
    1055983                /// true if expression is an lvalue
    1056984                static bool isLvalue( const ast::Expr * x ) {
    1057                         return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
     985                        return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() );
    1058986                }
    1059987
     
    1061989                        CandidateFinder finder{ symtab, tenv };
    1062990                        finder.find( addressExpr->arg );
    1063 
    1064                         if( finder.candidates.empty() ) return;
    1065 
    1066                         reason.code = NoMatch;
    1067 
    1068991                        for ( CandidateRef & r : finder.candidates ) {
    1069992                                if ( ! isLvalue( r->expr ) ) continue;
     
    10801003                        assert( toType );
    10811004                        toType = resolveTypeof( toType, symtab );
    1082                         // toType = SymTab::validateType( castExpr->location, toType, symtab );
     1005                        toType = SymTab::validateType( castExpr->location, toType, symtab );
    10831006                        toType = adjustExprType( toType, tenv, symtab );
    10841007
    10851008                        CandidateFinder finder{ symtab, tenv, toType };
    10861009                        finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    1087 
    1088                         if( !finder.candidates.empty() ) reason.code = NoMatch;
    10891010
    10901011                        CandidateList matches;
     
    10951016                                cand->env.extractOpenVars( open );
    10961017
    1097                                 // It is possible that a cast can throw away some values in a multiply-valued
    1098                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
    1099                                 // subexpression results that are cast directly. The candidate is invalid if it
     1018                                // It is possible that a cast can throw away some values in a multiply-valued 
     1019                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 
     1020                                // subexpression results that are cast directly. The candidate is invalid if it 
    11001021                                // has fewer results than there are types to cast to.
    11011022                                int discardedValues = cand->expr->result->size() - toType->size();
     
    11041025                                // unification run for side-effects
    11051026                                unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1106                                 Cost thisCost =
    1107                                         (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
    1108                             ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
    1109                             : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
    1110 
     1027                                Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env );
    11111028                                PRINT(
    11121029                                        std::cerr << "working on cast with result: " << toType << std::endl;
     
    11201037                                        // count one safe conversion for each value that is thrown away
    11211038                                        thisCost.incSafe( discardedValues );
    1122                                         CandidateRef newCand = std::make_shared<Candidate>(
    1123                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1124                                                 copy( cand->env ), move( open ), move( need ), cand->cost,
     1039                                        CandidateRef newCand = std::make_shared<Candidate>( 
     1040                                                restructureCast( cand->expr, toType, castExpr->isGenerated ), 
     1041                                                copy( cand->env ), move( open ), move( need ), cand->cost, 
    11251042                                                cand->cost + thisCost );
    11261043                                        inferParameters( newCand, matches );
     
    11401057                        finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    11411058                        for ( CandidateRef & r : finder.candidates ) {
    1142                                 addCandidate(
    1143                                         *r,
     1059                                addCandidate( 
     1060                                        *r, 
    11441061                                        new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    11451062                        }
    1146                 }
    1147 
    1148                 void postvisit( const ast::KeywordCastExpr * castExpr ) {
    1149                         const auto & loc = castExpr->location;
    1150                         assertf( castExpr->result, "Cast target should have been set in Validate." );
    1151                         auto ref = castExpr->result.strict_as<ast::ReferenceType>();
    1152                         auto inst = ref->base.strict_as<ast::StructInstType>();
    1153                         auto target = inst->base.get();
    1154 
    1155                         CandidateFinder finder{ symtab, tenv };
    1156 
    1157                         auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
    1158                                 for(auto & cand : found) {
    1159                                         const ast::Type * expr = cand->expr->result.get();
    1160                                         if(expect_ref) {
    1161                                                 auto res = dynamic_cast<const ast::ReferenceType*>(expr);
    1162                                                 if(!res) { continue; }
    1163                                                 expr = res->base.get();
    1164                                         }
    1165 
    1166                                         if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
    1167                                                 auto td = cand->env.lookup(*insttype);
    1168                                                 if(!td) { continue; }
    1169                                                 expr = td->bound.get();
    1170                                         }
    1171 
    1172                                         if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
    1173                                                 if(base->base == target) {
    1174                                                         candidates.push_back( std::move(cand) );
    1175                                                         reason.code = NoReason;
    1176                                                 }
    1177                                         }
    1178                                 }
    1179                         };
    1180 
    1181                         try {
    1182                                 // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd
    1183                                 // Clone is purely for memory management
    1184                                 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
    1185 
    1186                                 // don't prune here, since it's guaranteed all alternatives will have the same type
    1187                                 finder.find( tech1.get(), ResolvMode::withoutPrune() );
    1188                                 pick_alternatives(finder.candidates, false);
    1189 
    1190                                 return;
    1191                         } catch(SemanticErrorException & ) {}
    1192 
    1193                         // Fallback : turn (thread&)X into ($thread&)get_thread(X)
    1194                         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 })) };
    1195                         // don't prune here, since it's guaranteed all alternatives will have the same type
    1196                         finder.find( fallback.get(), ResolvMode::withoutPrune() );
    1197 
    1198                         pick_alternatives(finder.candidates, true);
    1199 
    1200                         // Whatever happens here, we have no more fallbacks
    12011063                }
    12021064
     
    12051067                        aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    12061068                        for ( CandidateRef & agg : aggFinder.candidates ) {
    1207                                 // it's okay for the aggregate expression to have reference type -- cast it to the
     1069                                // it's okay for the aggregate expression to have reference type -- cast it to the 
    12081070                                // base type to treat the aggregate as the referenced value
    12091071                                Cost addedCost = Cost::zero;
     
    12121074                                // find member of the given type
    12131075                                if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1214                                         addAggMembers(
     1076                                        addAggMembers( 
    12151077                                                structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    12161078                                } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1217                                         addAggMembers(
     1079                                        addAggMembers( 
    12181080                                                unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    12191081                                } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     
    12281090
    12291091                void postvisit( const ast::NameExpr * nameExpr ) {
    1230                         std::vector< ast::SymbolTable::IdData > declList;
    1231                         if (!selfFinder.otypeKeys.empty()) {
    1232                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    1233                                 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
    1234 
    1235                                 for (auto & otypeKey: selfFinder.otypeKeys) {
    1236                                         auto result = symtab.specialLookupId(kind, otypeKey);
    1237                                         declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
    1238                                 }
    1239                         }
    1240                         else {
    1241                                 declList = symtab.lookupId( nameExpr->name );
    1242                         }
     1092                        std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name );
    12431093                        PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
    1244 
    1245                         if( declList.empty() ) return;
    1246 
    1247                         reason.code = NoMatch;
    1248 
    12491094                        for ( auto & data : declList ) {
    12501095                                Cost cost = Cost::zero;
     
    12521097
    12531098                                CandidateRef newCand = std::make_shared<Candidate>(
    1254                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     1099                                        newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 
    12551100                                        cost );
    12561101                                PRINT(
     
    12621107                                        std::cerr << std::endl;
    12631108                                )
    1264                                 newCand->expr = ast::mutate_field(
    1265                                         newCand->expr.get(), &ast::Expr::result,
     1109                                newCand->expr = ast::mutate_field( 
     1110                                        newCand->expr.get(), &ast::Expr::result, 
    12661111                                        renameTyVars( newCand->expr->result ) );
    1267                                 // add anonymous member interpretations whenever an aggregate value type is seen
     1112                                // add anonymous member interpretations whenever an aggregate value type is seen 
    12681113                                // as a name expression
    12691114                                addAnonConversions( newCand );
     
    12751120                        // not sufficient to just pass `variableExpr` here, type might have changed since
    12761121                        // creation
    1277                         addCandidate(
     1122                        addCandidate( 
    12781123                                new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    12791124                }
     
    12851130                void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    12861131                        if ( sizeofExpr->type ) {
    1287                                 addCandidate(
    1288                                         new ast::SizeofExpr{
    1289                                                 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) },
     1132                                addCandidate( 
     1133                                        new ast::SizeofExpr{ 
     1134                                                sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 
    12901135                                        tenv );
    12911136                        } else {
     
    12961141                                CandidateList winners = findMinCost( finder.candidates );
    12971142                                if ( winners.size() != 1 ) {
    1298                                         SemanticError(
     1143                                        SemanticError( 
    12991144                                                sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    13001145                                }
     
    13091154                void postvisit( const ast::AlignofExpr * alignofExpr ) {
    13101155                        if ( alignofExpr->type ) {
    1311                                 addCandidate(
    1312                                         new ast::AlignofExpr{
    1313                                                 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) },
     1156                                addCandidate( 
     1157                                        new ast::AlignofExpr{ 
     1158                                                alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 
    13141159                                        tenv );
    13151160                        } else {
     
    13201165                                CandidateList winners = findMinCost( finder.candidates );
    13211166                                if ( winners.size() != 1 ) {
    1322                                         SemanticError(
     1167                                        SemanticError( 
    13231168                                                alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    13241169                                }
     
    13271172                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    13281173                                choice->cost = Cost::zero;
    1329                                 addCandidate(
     1174                                addCandidate( 
    13301175                                        *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    13311176                        }
     
    13331178
    13341179                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
    1335                         const ast::BaseInstType * aggInst;
     1180                        const ast::ReferenceToType * aggInst;
    13361181                        if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
    13371182                        else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
     
    13401185                        for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    13411186                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1342                                 addCandidate(
     1187                                addCandidate( 
    13431188                                        new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    13441189                        }
     
    13611206                        finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    13621207                        if ( finder2.candidates.empty() ) return;
    1363 
    1364                         reason.code = NoMatch;
    13651208
    13661209                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    13751218
    13761219                                        addCandidate(
    1377                                                 new ast::LogicalExpr{
     1220                                                new ast::LogicalExpr{ 
    13781221                                                        logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    13791222                                                move( env ), move( open ), move( need ), r1->cost + r2->cost );
     
    13971240                        finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    13981241                        if ( finder3.candidates.empty() ) return;
    1399 
    1400                         reason.code = NoMatch;
    14011242
    14021243                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    14151256                                                ast::AssertionSet have;
    14161257
    1417                                                 // unify true and false results, then infer parameters to produce new
     1258                                                // unify true and false results, then infer parameters to produce new 
    14181259                                                // candidates
    14191260                                                ast::ptr< ast::Type > common;
    1420                                                 if (
    1421                                                         unify(
    1422                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab,
    1423                                                                 common )
     1261                                                if ( 
     1262                                                        unify( 
     1263                                                                r2->expr->result, r3->expr->result, env, need, have, open, symtab, 
     1264                                                                common ) 
    14241265                                                ) {
    14251266                                                        // generate typed expression
    1426                                                         ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
     1267                                                        ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 
    14271268                                                                conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    14281269                                                        newExpr->result = common ? common : r2->expr->result;
    14291270                                                        // convert both options to result type
    14301271                                                        Cost cost = r1->cost + r2->cost + r3->cost;
    1431                                                         newExpr->arg2 = computeExpressionConversionCost(
     1272                                                        newExpr->arg2 = computeExpressionConversionCost( 
    14321273                                                                newExpr->arg2, newExpr->result, symtab, env, cost );
    14331274                                                        newExpr->arg3 = computeExpressionConversionCost(
     
    14461287                        ast::TypeEnvironment env{ tenv };
    14471288                        ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
    1448 
     1289                       
    14491290                        CandidateFinder finder2{ symtab, env };
    14501291                        finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     
    14761317                        finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    14771318                        if ( finder2.candidates.empty() ) return;
    1478 
    1479                         reason.code = NoMatch;
    14801319
    14811320                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    14911330
    14921331                                        ast::ptr< ast::Type > common;
    1493                                         if (
    1494                                                 unify(
    1495                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab,
    1496                                                         common )
     1332                                        if ( 
     1333                                                unify( 
     1334                                                        r1->expr->result, r2->expr->result, env, need, have, open, symtab, 
     1335                                                        common ) 
    14971336                                        ) {
    14981337                                                // generate new expression
    1499                                                 ast::RangeExpr * newExpr =
     1338                                                ast::RangeExpr * newExpr = 
    15001339                                                        new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    15011340                                                newExpr->result = common ? common : r1->expr->result;
    15021341                                                // add candidate
    15031342                                                CandidateRef newCand = std::make_shared<Candidate>(
    1504                                                         newExpr, move( env ), move( open ), move( need ),
     1343                                                        newExpr, move( env ), move( open ), move( need ), 
    15051344                                                        r1->cost + r2->cost );
    15061345                                                inferParameters( newCand, candidates );
     
    15111350
    15121351                void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1513                         std::vector< CandidateFinder > subCandidates =
     1352                        std::vector< CandidateFinder > subCandidates = 
    15141353                                selfFinder.findSubExprs( tupleExpr->exprs );
    15151354                        std::vector< CandidateList > possibilities;
     
    15311370
    15321371                                addCandidate(
    1533                                         new ast::TupleExpr{ tupleExpr->location, move( exprs ) },
     1372                                        new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 
    15341373                                        move( env ), move( open ), move( need ), sumCost( subs ) );
    15351374                        }
     
    15711410                                // calculate target type
    15721411                                const ast::Type * toType = resolveTypeof( initAlt.type, symtab );
    1573                                 // toType = SymTab::validateType( initExpr->location, toType, symtab );
     1412                                toType = SymTab::validateType( initExpr->location, toType, symtab );
    15741413                                toType = adjustExprType( toType, tenv, symtab );
    1575                                 // The call to find must occur inside this loop, otherwise polymorphic return
    1576                                 // types are not bound to the initialization type, since return type variables are
    1577                                 // only open for the duration of resolving the UntypedExpr.
     1414                                // The call to find must occur inside this loop, otherwise polymorphic return 
     1415                                // types are not bound to the initialization type, since return type variables are 
     1416                                // only open for the duration of resolving the UntypedExpr. 
    15781417                                CandidateFinder finder{ symtab, tenv, toType };
    15791418                                finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    15801419                                for ( CandidateRef & cand : finder.candidates ) {
    1581                                         if(reason.code == NotFound) reason.code = NoMatch;
    1582 
    15831420                                        ast::TypeEnvironment env{ cand->env };
    15841421                                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     
    15891426                                        )
    15901427
    1591                                         // It is possible that a cast can throw away some values in a multiply-valued
    1592                                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
    1593                                         // the subexpression results that are cast directly. The candidate is invalid
     1428                                        // It is possible that a cast can throw away some values in a multiply-valued 
     1429                                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 
     1430                                        // the subexpression results that are cast directly. The candidate is invalid 
    15941431                                        // if it has fewer results than there are types to cast to.
    15951432                                        int discardedValues = cand->expr->result->size() - toType->size();
     
    15971434
    15981435                                        // unification run for side-effects
    1599                                         bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
    1600                                         (void) canUnify;
    1601                                         Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1602                                                 symtab, env );
    1603                                         PRINT(
    1604                                                 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1605                                                         symtab, env );
    1606                                                 std::cerr << "Considering initialization:";
    1607                                                 std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
    1608                                                 std::cerr << std::endl << "  TO: "   << toType             << std::endl;
    1609                                                 std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
    1610                                                 std::cerr << std::endl << "  Legacy cost " << legacyCost;
    1611                                                 std::cerr << std::endl << "  New cost " << thisCost;
    1612                                                 std::cerr << std::endl;
    1613                                         )
     1436                                        unify( toType, cand->expr->result, env, need, have, open, symtab );
     1437                                        Cost thisCost = castCost( cand->expr->result, toType, symtab, env );
     1438                                       
    16141439                                        if ( thisCost != Cost::infinity ) {
    16151440                                                // count one safe conversion for each value that is thrown away
    16161441                                                thisCost.incSafe( discardedValues );
    1617                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1618                                                         new ast::InitExpr{
    1619                                                                 initExpr->location, restructureCast( cand->expr, toType ),
    1620                                                                 initAlt.designation },
    1621                                                         move(env), move( open ), move( need ), cand->cost, thisCost );
     1442                                                CandidateRef newCand = std::make_shared<Candidate>( 
     1443                                                        new ast::InitExpr{ 
     1444                                                                initExpr->location, restructureCast( cand->expr, toType ), 
     1445                                                                initAlt.designation }, 
     1446                                                        copy( cand->env ), move( open ), move( need ), cand->cost, thisCost );
    16221447                                                inferParameters( newCand, matches );
    16231448                                        }
    16241449                                }
    1625 
    16261450                        }
    16271451
     
    16451469        };
    16461470
    1647         // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
    1648         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1471        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    16491472        /// return type. Skips ambiguous candidates.
    1650 
    1651 } // anonymous namespace
    1652 
    1653 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
    1654         struct PruneStruct {
    1655                 CandidateRef candidate;
    1656                 bool ambiguous;
    1657 
    1658                 PruneStruct() = default;
    1659                 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
    1660         };
    1661 
    1662         // find lowest-cost candidate for each type
    1663         std::unordered_map< std::string, PruneStruct > selected;
    1664         // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
    1665         std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
    1666         for ( CandidateRef & candidate : candidates ) {
    1667                 std::string mangleName;
    1668                 {
    1669                         ast::ptr< ast::Type > newType = candidate->expr->result;
    1670                         assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
    1671                         candidate->env.apply( newType );
    1672                         mangleName = Mangle::mangle( newType );
    1673                 }
    1674 
    1675                 auto found = selected.find( mangleName );
    1676                 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
    1677                         PRINT(
    1678                                 std::cerr << "cost " << candidate->cost << " loses to "
    1679                                         << found->second.candidate->cost << std::endl;
    1680                         )
    1681                         continue;
    1682                 }
    1683 
    1684                 // xxx - when do satisfyAssertions produce more than 1 result?
    1685                 // this should only happen when initial result type contains
    1686                 // unbound type parameters, then it should never be pruned by
    1687                 // the previous step, since renameTyVars guarantees the mangled name
    1688                 // is unique.
    1689                 CandidateList satisfied;
    1690                 bool needRecomputeKey = false;
    1691                 if (candidate->need.empty()) {
    1692                         satisfied.emplace_back(candidate);
    1693                 }
    1694                 else {
    1695                         satisfyAssertions(candidate, localSyms, satisfied, errors);
    1696                         needRecomputeKey = true;
    1697                 }
    1698 
    1699                 for (auto & newCand : satisfied) {
    1700                         // recomputes type key, if satisfyAssertions changed it
    1701                         if (needRecomputeKey)
     1473        CandidateList pruneCandidates( CandidateList & candidates ) {
     1474                struct PruneStruct {
     1475                        CandidateRef candidate;
     1476                        bool ambiguous;
     1477
     1478                        PruneStruct() = default;
     1479                        PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
     1480                };
     1481
     1482                // find lowest-cost candidate for each type
     1483                std::unordered_map< std::string, PruneStruct > selected;
     1484                for ( CandidateRef & candidate : candidates ) {
     1485                        std::string mangleName;
    17021486                        {
    1703                                 ast::ptr< ast::Type > newType = newCand->expr->result;
    1704                                 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
    1705                                 newCand->env.apply( newType );
     1487                                ast::ptr< ast::Type > newType = candidate->expr->result;
     1488                                candidate->env.apply( newType );
    17061489                                mangleName = Mangle::mangle( newType );
    17071490                        }
     1491
    17081492                        auto found = selected.find( mangleName );
    17091493                        if ( found != selected.end() ) {
    1710                                 if ( newCand->cost < found->second.candidate->cost ) {
     1494                                if ( candidate->cost < found->second.candidate->cost ) {
    17111495                                        PRINT(
    1712                                                 std::cerr << "cost " << newCand->cost << " beats "
     1496                                                std::cerr << "cost " << candidate->cost << " beats "
    17131497                                                        << found->second.candidate->cost << std::endl;
    17141498                                        )
    17151499
    1716                                         found->second = PruneStruct{ newCand };
    1717                                 } else if ( newCand->cost == found->second.candidate->cost ) {
    1718                                         // if one of the candidates contains a deleted identifier, can pick the other,
    1719                                         // since deleted expressions should not be ambiguous if there is another option
     1500                                        found->second = PruneStruct{ candidate };
     1501                                } else if ( candidate->cost == found->second.candidate->cost ) {
     1502                                        // if one of the candidates contains a deleted identifier, can pick the other, 
     1503                                        // since deleted expressions should not be ambiguous if there is another option 
    17201504                                        // that is at least as good
    1721                                         if ( findDeletedExpr( newCand->expr ) ) {
     1505                                        if ( findDeletedExpr( candidate->expr ) ) {
    17221506                                                // do nothing
    17231507                                                PRINT( std::cerr << "candidate is deleted" << std::endl; )
    17241508                                        } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
    17251509                                                PRINT( std::cerr << "current is deleted" << std::endl; )
    1726                                                 found->second = PruneStruct{ newCand };
     1510                                                found->second = PruneStruct{ candidate };
    17271511                                        } else {
    17281512                                                PRINT( std::cerr << "marking ambiguous" << std::endl; )
    17291513                                                found->second.ambiguous = true;
    17301514                                        }
    1731                                 } else {
    1732                                         // xxx - can satisfyAssertions increase the cost?
     1515                                } else {
    17331516                                        PRINT(
    1734                                                 std::cerr << "cost " << newCand->cost << " loses to "
     1517                                                std::cerr << "cost " << candidate->cost << " loses to "
    17351518                                                        << found->second.candidate->cost << std::endl;
    1736                                         )       
     1519                                        )
    17371520                                }
    17381521                        } else {
    1739                                 selected.emplace_hint( found, mangleName, newCand );
    1740                         }
    1741                 }
     1522                                selected.emplace_hint( found, mangleName, candidate );
     1523                        }
     1524                }
     1525
     1526                // report unambiguous min-cost candidates
     1527                CandidateList out;
     1528                for ( auto & target : selected ) {
     1529                        if ( target.second.ambiguous ) continue;
     1530
     1531                        CandidateRef cand = target.second.candidate;
     1532                       
     1533                        ast::ptr< ast::Type > newResult = cand->expr->result;
     1534                        cand->env.applyFree( newResult );
     1535                        cand->expr = ast::mutate_field(
     1536                                cand->expr.get(), &ast::Expr::result, move( newResult ) );
     1537                       
     1538                        out.emplace_back( cand );
     1539                }
     1540                return out;
    17421541        }
    17431542
    1744         // report unambiguous min-cost candidates
    1745         // CandidateList out;
    1746         for ( auto & target : selected ) {
    1747                 if ( target.second.ambiguous ) continue;
    1748 
    1749                 CandidateRef cand = target.second.candidate;
    1750 
    1751                 ast::ptr< ast::Type > newResult = cand->expr->result;
    1752                 cand->env.applyFree( newResult );
    1753                 cand->expr = ast::mutate_field(
    1754                         cand->expr.get(), &ast::Expr::result, move( newResult ) );
    1755 
    1756                 out.emplace_back( cand );
    1757         }
    1758         // if everything is lost in satisfyAssertions, report the error
    1759         return !selected.empty();
    1760 }
     1543} // anonymous namespace
    17611544
    17621545void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
     
    17661549
    17671550        if ( mode.failFast && candidates.empty() ) {
    1768                 switch(finder.core.reason.code) {
    1769                 case Finder::NotFound:
    1770                         { SemanticError( expr, "No alternatives for expression " ); break; }
    1771                 case Finder::NoMatch:
    1772                         { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
    1773                 case Finder::ArgsToFew:
    1774                 case Finder::ArgsToMany:
    1775                 case Finder::RetsToFew:
    1776                 case Finder::RetsToMany:
    1777                 case Finder::NoReason:
    1778                 default:
    1779                         { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
    1780                 }
     1551                SemanticError( expr, "No reasonable alternatives for expression " );
    17811552        }
    17821553
    1783         /*
    17841554        if ( mode.satisfyAssns || mode.prune ) {
    17851555                // trim candidates to just those where the assertions are satisfiable
     
    17881558                std::vector< std::string > errors;
    17891559                for ( CandidateRef & candidate : candidates ) {
    1790                         satisfyAssertions( candidate, localSyms, satisfied, errors );
     1560                        satisfyAssertions( candidate, symtab, satisfied, errors );
    17911561                }
    17921562
     
    18041574                candidates = move( satisfied );
    18051575        }
    1806         */
    18071576
    18081577        if ( mode.prune ) {
     
    18131582                )
    18141583
    1815                 CandidateList pruned;
    1816                 std::vector<std::string> errors;
    1817                 bool found = pruneCandidates( candidates, pruned, errors );
    1818 
     1584                CandidateList pruned = pruneCandidates( candidates );
     1585               
    18191586                if ( mode.failFast && pruned.empty() ) {
    18201587                        std::ostringstream stream;
    1821                         if (found) {           
    1822                                 CandidateList winners = findMinCost( candidates );
    1823                                 stream << "Cannot choose between " << winners.size() << " alternatives for "
    1824                                         "expression\n";
    1825                                 ast::print( stream, expr );
    1826                                 stream << " Alternatives are:\n";
    1827                                 print( stream, winners, 1 );
    1828                                 SemanticError( expr->location, stream.str() );
    1829                         }
    1830                         else {
    1831                                 stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1832                                 for ( const auto& err : errors ) {
    1833                                         stream << err;
    1834                                 }
    1835                                 SemanticError( expr->location, stream.str() );
    1836                         }
     1588                        CandidateList winners = findMinCost( candidates );
     1589                        stream << "Cannot choose between " << winners.size() << " alternatives for "
     1590                                "expression\n";
     1591                        ast::print( stream, expr );
     1592                        stream << " Alternatives are:\n";
     1593                        print( stream, winners, 1 );
     1594                        SemanticError( expr->location, stream.str() );
    18371595                }
    18381596
     
    18441602                )
    18451603                PRINT(
    1846                         std::cerr << "there are " << candidates.size() << " alternatives after elimination"
     1604                        std::cerr << "there are " << candidates.size() << " alternatives after elimination" 
    18471605                                << std::endl;
    18481606                )
    18491607        }
    18501608
    1851         // adjust types after pruning so that types substituted by pruneAlternatives are correctly
     1609        // adjust types after pruning so that types substituted by pruneAlternatives are correctly 
    18521610        // adjusted
    18531611        if ( mode.adjust ) {
    18541612                for ( CandidateRef & r : candidates ) {
    1855                         r->expr = ast::mutate_field(
    1856                                 r->expr.get(), &ast::Expr::result,
    1857                                 adjustExprType( r->expr->result, r->env, localSyms ) );
     1613                        r->expr = ast::mutate_field( 
     1614                                r->expr.get(), &ast::Expr::result, 
     1615                                adjustExprType( r->expr->result, r->env, symtab ) );
    18581616                }
    18591617        }
     
    18671625}
    18681626
    1869 std::vector< CandidateFinder > CandidateFinder::findSubExprs(
    1870         const std::vector< ast::ptr< ast::Expr > > & xs
     1627std::vector< CandidateFinder > CandidateFinder::findSubExprs( 
     1628        const std::vector< ast::ptr< ast::Expr > > & xs 
    18711629) {
    18721630        std::vector< CandidateFinder > out;
    18731631
    18741632        for ( const auto & x : xs ) {
    1875                 out.emplace_back( localSyms, env );
     1633                out.emplace_back( symtab, env );
    18761634                out.back().find( x, ResolvMode::withAdjustment() );
    1877 
     1635               
    18781636                PRINT(
    18791637                        std::cerr << "findSubExprs" << std::endl;
Note: See TracChangeset for help on using the changeset viewer.