Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/AlternativeFinder.cc

    rfae6f21 r11094d9  
    7676
    7777        namespace {
    78                 void printAlts( const AltList &list, std::ostream &os, int indent = 0 ) {
     78                void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt = 0 ) {
     79                        Indenter indent = { Indenter::tabsize, indentAmt };
    7980                        for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
    8081                                i->print( os, indent );
     
    122123                                                )
    123124                                                mapPlace->second.isAmbiguous = true;
     125                                        } else {
     126                                                PRINT(
     127                                                        std::cerr << "cost " << candidate->cost << " loses to " << mapPlace->second.candidate->cost << std::endl;
     128                                                )
    124129                                        }
    125130                                } else {
     
    127132                                }
    128133                        }
    129 
    130                         PRINT(
    131                                 std::cerr << "there are " << selected.size() << " alternatives before elimination" << std::endl;
    132                         )
    133134
    134135                        // accept the alternatives that were unambiguous
     
    145146                        expr->get_result()->accept( global_renamer );
    146147                }
    147 
    148                 void referenceToRvalueConversion( Expression *& expr ) {
    149                         if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
    150                                 // cast away reference from expr
    151                                 expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
    152                         }
    153                 }
    154148        } // namespace
     149
     150        void referenceToRvalueConversion( Expression *& expr ) {
     151                if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
     152                        // cast away reference from expr
     153                        expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
     154                }
     155        }
    155156
    156157        template< typename InputIterator, typename OutputIterator >
     
    175176        }
    176177
    177         void AlternativeFinder::find( Expression *expr, bool adjust, bool prune ) {
     178        void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
    178179                expr->accept( *this );
    179                 if ( alternatives.empty() ) {
     180                if ( failFast && alternatives.empty() ) {
    180181                        throw SemanticError( "No reasonable alternatives for expression ", expr );
    181182                }
    182                 for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
    183                         if ( adjust ) {
    184                                 adjustExprType( i->expr->get_result(), i->env, indexer );
    185                         }
    186                 }
    187183                if ( prune ) {
     184                        auto oldsize = alternatives.size();
    188185                        PRINT(
    189186                                std::cerr << "alternatives before prune:" << std::endl;
     
    192189                        AltList::iterator oldBegin = alternatives.begin();
    193190                        pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) );
    194                         if ( alternatives.begin() == oldBegin ) {
     191                        if ( failFast && alternatives.begin() == oldBegin ) {
    195192                                std::ostringstream stream;
    196193                                AltList winners;
    197194                                findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
    198                                 stream << "Cannot choose between " << winners.size() << " alternatives for expression ";
     195                                stream << "Cannot choose between " << winners.size() << " alternatives for expression\n";
    199196                                expr->print( stream );
    200                                 stream << "Alternatives are:";
    201                                 printAlts( winners, stream, 8 );
     197                                stream << "Alternatives are:\n";
     198                                printAlts( winners, stream, 1 );
    202199                                throw SemanticError( stream.str() );
    203200                        }
    204201                        alternatives.erase( oldBegin, alternatives.end() );
     202                        PRINT(
     203                                std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
     204                        )
    205205                        PRINT(
    206206                                std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl;
    207207                        )
     208                }
     209                // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
     210                for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
     211                        if ( adjust ) {
     212                                adjustExprType( i->expr->get_result(), i->env, indexer );
     213                        }
    208214                }
    209215
     
    215221        }
    216222
    217         void AlternativeFinder::findWithAdjustment( Expression *expr, bool prune ) {
    218                 find( expr, true, prune );
     223        void AlternativeFinder::findWithAdjustment( Expression *expr ) {
     224                find( expr, true );
     225        }
     226
     227        void AlternativeFinder::findWithoutPrune( Expression * expr ) {
     228                find( expr, true, false );
     229        }
     230
     231        void AlternativeFinder::maybeFind( Expression * expr ) {
     232                find( expr, true, true, false );
    219233        }
    220234
     
    299313                Cost convCost = conversionCost( actualType, formalType, indexer, env );
    300314                PRINT(
    301                         std::cerr << std::endl << "cost is" << convCost << std::endl;
     315                        std::cerr << std::endl << "cost is " << convCost << std::endl;
    302316                )
    303317                if ( convCost == Cost::infinity ) {
     
    305319                }
    306320                convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) );
     321                PRINT(
     322                        std::cerr << "cost with polycost is " << convCost << std::endl;
     323                )
    307324                return convCost;
    308325        }
     
    310327        Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
    311328                Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
    312                 // if ( convCost != Cost::zero ) {
    313 
    314                 // xxx - temporary -- ignore poly cost, since this causes some polymorphic functions to be cast, which causes the specialize
    315                 // pass to try to specialize them, which currently does not work. Once that is fixed, remove the next 3 lines and uncomment the
    316                 // previous line.
     329
     330                // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion.
     331                // ignore poly cost for now, since this requires resolution of the cast to infer parameters and this
     332                // does not currently work for the reason stated below.
    317333                Cost tmpCost = convCost;
    318334                tmpCost.incPoly( -tmpCost.get_polyCost() );
     
    357373                                if ( function->get_isVarArgs() ) {
    358374                                        convCost.incUnsafe();
     375                                        PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
    359376                                        // convert reference-typed expressions to value-typed expressions
    360377                                        referenceToRvalueConversion( *actualExpr );
     
    365382                        }
    366383                        Type * formalType = (*formal)->get_type();
    367                         PRINT(
    368                                 std::cerr << std::endl << "converting ";
    369                                 actualType->print( std::cerr, 8 );
    370                                 std::cerr << std::endl << " to ";
    371                                 formalType->print( std::cerr, 8 );
    372                                 std::cerr << std::endl << "environment is: ";
    373                                 alt.env.print( std::cerr, 8 );
    374                                 std::cerr << std::endl;
    375                         )
    376384                        convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
    377385                        ++formal; // can't be in for-loop update because of the continue
     
    481489                                Alternative newerAlt( newAlt );
    482490                                newerAlt.env = newEnv;
    483                                 assert( (*candidate)->get_uniqueId() );
     491                                assertf( (*candidate)->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( *candidate ).c_str() );
    484492                                DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) );
    485493
     
    507515                                        std::cerr << std::endl;
    508516                                )
    509                                 ApplicationExpr *appExpr = static_cast< ApplicationExpr* >( newerAlt.expr );
    510517                                // follow the current assertion's ID chain to find the correct set of inferred parameters to add the candidate to (i.e. the set of inferred parameters belonging to the entity which requested the assertion parameter).
    511                                 InferredParams * inferParameters = &appExpr->get_inferParams();
     518                                InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
    512519                                for ( UniqueId id : cur->second.idChain ) {
    513520                                        inferParameters = (*inferParameters)[ id ].inferParams.get();
     
    574581                std::vector<unsigned> tupleEls;  /// Number of elements in current tuple element(s)
    575582
    576                 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 
     583                ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
    577584                                const OpenVarSet& openVars)
    578585                        : actuals(), env(env), need(need), have(have), openVars(openVars), nextArg(0),
    579586                          expls(), nextExpl(0), tupleEls() {}
    580                
     587
    581588                /// Starts a new tuple expression
    582589                void beginTuple() {
     
    613620
    614621        /// Instantiates an argument to match a formal, returns false if no results left
    615         bool instantiateArgument( Type* formalType, Initializer* initializer, 
    616                         const std::vector< AlternativeFinder >& args, 
    617                         std::vector<ArgPack>& results, std::vector<ArgPack>& nextResults, 
     622        bool instantiateArgument( Type* formalType, Initializer* initializer,
     623                        const std::vector< AlternativeFinder >& args,
     624                        std::vector<ArgPack>& results, std::vector<ArgPack>& nextResults,
    618625                        const SymTab::Indexer& indexer ) {
    619626                if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
     
    622629                        for ( Type* type : *tupleType ) {
    623630                                // xxx - dropping initializer changes behaviour from previous, but seems correct
    624                                 if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) ) 
     631                                if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) )
    625632                                        return false;
    626633                        }
     
    651658                                                Type* argType = result.actuals.back().expr->get_result();
    652659                                                if ( result.tupleEls.back() == 1 && Tuples::isTtype( argType ) ) {
    653                                                         // the case where a ttype value is passed directly is special, e.g. for 
     660                                                        // the case where a ttype value is passed directly is special, e.g. for
    654661                                                        // argument forwarding purposes
    655662                                                        // xxx - what if passing multiple arguments, last of which is ttype?
    656                                                         // xxx - what would happen if unify was changed so that unifying tuple 
     663                                                        // xxx - what would happen if unify was changed so that unifying tuple
    657664                                                        // types flattened both before unifying lists? then pass in TupleType
    658665                                                        // (ttype) below.
     
    664671                                                }
    665672                                                // check unification for ttype before adding to final
    666                                                 if ( unify( ttype, argType, result.env, result.need, result.have, 
     673                                                if ( unify( ttype, argType, result.env, result.need, result.have,
    667674                                                                result.openVars, indexer ) ) {
    668675                                                        finalResults.push_back( std::move(result) );
     
    677684                                                aResult.env.addActual( actual.env, aResult.openVars );
    678685                                                Cost cost = actual.cost;
    679                
     686
    680687                                                // explode argument
    681688                                                std::vector<Alternative> exploded;
    682689                                                Tuples::explode( actual, indexer, back_inserter( exploded ) );
    683                                                
     690
    684691                                                // add exploded argument to tuple
    685692                                                for ( Alternative& aActual : exploded ) {
     
    699706                        return ! results.empty();
    700707                }
    701                
     708
    702709                // iterate each current subresult
    703710                for ( unsigned iResult = 0; iResult < results.size(); ++iResult ) {
     
    717724                                        std::cerr << std::endl;
    718725                                )
    719                                
    720                                 if ( unify( formalType, actualType, result.env, result.need, result.have, 
     726
     727                                if ( unify( formalType, actualType, result.env, result.need, result.have,
    721728                                                result.openVars, indexer ) ) {
    722729                                        ++result.nextExpl;
     
    729736                                if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
    730737                                        if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
    731                                                 if ( unify( formalType, cnst->get_type(), result.env, result.need, 
     738                                                if ( unify( formalType, cnst->get_type(), result.env, result.need,
    732739                                                                result.have, result.openVars, indexer ) ) {
    733740                                                        nextResults.push_back( std::move(result.withArg( cnstExpr )) );
     
    784791                results.swap( nextResults );
    785792                nextResults.clear();
    786                
     793
    787794                return ! results.empty();
    788795        }
    789796
    790797        template<typename OutputIterator>
    791         void AlternativeFinder::makeFunctionAlternatives( const Alternative& func,
    792                         FunctionType* funcType, const std::vector< AlternativeFinder >& args,
     798        void AlternativeFinder::makeFunctionAlternatives( const Alternative &func,
     799                        FunctionType *funcType, const std::vector< AlternativeFinder > &args,
    793800                        OutputIterator out ) {
    794801                OpenVarSet funcOpenVars;
    795802                AssertionSet funcNeed, funcHave;
    796                 TypeEnvironment funcEnv;
     803                TypeEnvironment funcEnv( func.env );
    797804                makeUnifiableVars( funcType, funcOpenVars, funcNeed );
    798                 // add all type variables as open variables now so that those not used in the parameter 
     805                // add all type variables as open variables now so that those not used in the parameter
    799806                // list are still considered open.
    800807                funcEnv.add( funcType->get_forall() );
     
    802809                if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
    803810                        // attempt to narrow based on expected target type
    804                         Type* returnType = funcType->get_returnVals().front()->get_type();
    805                         if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars, 
     811                        Type * returnType = funcType->get_returnVals().front()->get_type();
     812                        if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
    806813                                        indexer ) ) {
    807814                                // unification failed, don't pursue this function alternative
     
    815822                for ( DeclarationWithType* formal : funcType->get_parameters() ) {
    816823                        ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
    817                         if ( ! instantiateArgument( 
     824                        if ( ! instantiateArgument(
    818825                                        obj->get_type(), obj->get_init(), args, results, nextResults, indexer ) )
    819826                                return;
     
    897904
    898905                std::vector< AlternativeFinder > argAlternatives;
    899                 findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), 
     906                findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
    900907                        back_inserter( argAlternatives ) );
    901908
     
    905912
    906913                // find function operators
     914                static NameExpr *opExpr = new NameExpr( "?()" );
    907915                AlternativeFinder funcOpFinder( indexer, env );
    908                 NameExpr *opExpr = new NameExpr( "?()" );
    909                 try {
    910                         funcOpFinder.findWithAdjustment( opExpr );
    911                 } catch( SemanticError &e ) {
    912                         // it's ok if there aren't any defined function ops
    913                 }
     916                // it's ok if there aren't any defined function ops
     917                funcOpFinder.maybeFind( opExpr);
    914918                PRINT(
    915919                        std::cerr << "known function ops:" << std::endl;
    916                         printAlts( funcOpFinder.alternatives, std::cerr, 8 );
     920                        printAlts( funcOpFinder.alternatives, std::cerr, 1 );
    917921                )
    918922
     
    930934                                                Alternative newFunc( *func );
    931935                                                referenceToRvalueConversion( newFunc.expr );
    932                                                 makeFunctionAlternatives( newFunc, function, argAlternatives, 
     936                                                makeFunctionAlternatives( newFunc, function, argAlternatives,
    933937                                                        std::back_inserter( candidates ) );
    934938                                        }
     
    939943                                                        Alternative newFunc( *func );
    940944                                                        referenceToRvalueConversion( newFunc.expr );
    941                                                         makeFunctionAlternatives( newFunc, function, argAlternatives, 
     945                                                        makeFunctionAlternatives( newFunc, function, argAlternatives,
    942946                                                                std::back_inserter( candidates ) );
    943947                                                } // if
    944948                                        } // if
    945                                 }                       
     949                                }
    946950                        } catch ( SemanticError &e ) {
    947951                                errors.append( e );
     
    958962                                try {
    959963                                        // check if type is a pointer to function
    960                                         if ( PointerType* pointer = dynamic_cast<PointerType*>( 
     964                                        if ( PointerType* pointer = dynamic_cast<PointerType*>(
    961965                                                        funcOp->expr->get_result()->stripReferences() ) ) {
    962                                                 if ( FunctionType* function = 
     966                                                if ( FunctionType* function =
    963967                                                                dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
    964968                                                        Alternative newFunc( *funcOp );
    965969                                                        referenceToRvalueConversion( newFunc.expr );
    966                                                         makeFunctionAlternatives( newFunc, function, argAlternatives, 
     970                                                        makeFunctionAlternatives( newFunc, function, argAlternatives,
    967971                                                                std::back_inserter( candidates ) );
    968972                                                }
     
    10031007                candidates.splice( candidates.end(), alternatives );
    10041008
    1005                 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( alternatives ) );
     1009                // use a new list so that alternatives are not examined by addAnonConversions twice.
     1010                AltList winners;
     1011                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
    10061012
    10071013                // function may return struct or union value, in which case we need to add alternatives for implicit
    10081014                // conversions to each of the anonymous members, must happen after findMinCost since anon conversions
    10091015                // are never the cheapest expression
    1010                 for ( const Alternative & alt : alternatives ) {
     1016                for ( const Alternative & alt : winners ) {
    10111017                        addAnonConversions( alt );
    10121018                }
     1019                alternatives.splice( alternatives.begin(), winners );
    10131020
    10141021                if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
     
    10281035        bool isLvalue( Expression *expr ) {
    10291036                // xxx - recurse into tuples?
    1030                 return expr->has_result() && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
     1037                return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
    10311038        }
    10321039
     
    11031110                                thisCost.incSafe( discardedValues );
    11041111                                Alternative newAlt( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost );
    1105                                 // xxx - this doesn't work at the moment, since inferParameters requires an ApplicationExpr as the alternative.
    1106                                 // Once this works, it should be possible to infer parameters on a cast expression and specialize any function.
    1107 
    1108                                 // inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
    1109                                 candidates.emplace_back( std::move( newAlt ) );
     1112                                inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
    11101113                        } // if
    11111114                } // for
     
    11231126                AlternativeFinder finder( indexer, env );
    11241127                // don't prune here, since it's guaranteed all alternatives will have the same type
    1125                 // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
    1126                 finder.findWithAdjustment( castExpr->get_arg(), false );
     1128                finder.findWithoutPrune( castExpr->get_arg() );
    11271129                for ( Alternative & alt : finder.alternatives ) {
    11281130                        alternatives.push_back( Alternative(
     
    11631165                PRINT( std::cerr << "nameExpr is " << nameExpr->get_name() << std::endl; )
    11641166                for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) {
    1165                         VariableExpr newExpr( *i, nameExpr->get_argName() );
     1167                        VariableExpr newExpr( *i );
    11661168                        alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
    11671169                        PRINT(
     
    13981400                findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), back_inserter( subExprAlternatives ) );
    13991401                std::list< AltList > possibilities;
    1400                 // TODO re-write to use iterative method
    14011402                combos( subExprAlternatives.begin(), subExprAlternatives.end(), back_inserter( possibilities ) );
    14021403                for ( std::list< AltList >::const_iterator i = possibilities.begin(); i != possibilities.end(); ++i ) {
     
    14221423                // don't prune here, since it's guaranteed all alternatives will have the same type
    14231424                // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
    1424                 finder.findWithAdjustment( ctorExpr->get_callExpr(), false );
     1425                finder.findWithoutPrune( ctorExpr->get_callExpr() );
    14251426                for ( Alternative & alt : finder.alternatives ) {
    14261427                        alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
     
    14591460                // O(N^2) checks of d-types with e-types
    14601461                for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
    1461                         Type * toType = resolveTypeof( initAlt.type, indexer );
     1462                        Type * toType = resolveTypeof( initAlt.type->clone(), indexer );
    14621463                        SymTab::validateType( toType, &indexer );
    14631464                        adjustExprType( toType, env, indexer );
     
    14881489                                        // count one safe conversion for each value that is thrown away
    14891490                                        thisCost.incSafe( discardedValues );
    1490                                         candidates.push_back( Alternative( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost ) );
     1491                                        Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
     1492                                        inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
    14911493                                }
    14921494                        }
Note: See TracChangeset for help on using the changeset viewer.