- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/AlternativeFinder.cc
rfae6f21 r11094d9 76 76 77 77 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 }; 79 80 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) { 80 81 i->print( os, indent ); … … 122 123 ) 123 124 mapPlace->second.isAmbiguous = true; 125 } else { 126 PRINT( 127 std::cerr << "cost " << candidate->cost << " loses to " << mapPlace->second.candidate->cost << std::endl; 128 ) 124 129 } 125 130 } else { … … 127 132 } 128 133 } 129 130 PRINT(131 std::cerr << "there are " << selected.size() << " alternatives before elimination" << std::endl;132 )133 134 134 135 // accept the alternatives that were unambiguous … … 145 146 expr->get_result()->accept( global_renamer ); 146 147 } 147 148 void referenceToRvalueConversion( Expression *& expr ) {149 if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {150 // cast away reference from expr151 expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );152 }153 }154 148 } // 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 } 155 156 156 157 template< typename InputIterator, typename OutputIterator > … … 175 176 } 176 177 177 void AlternativeFinder::find( Expression *expr, bool adjust, bool prune ) {178 void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) { 178 179 expr->accept( *this ); 179 if ( alternatives.empty() ) {180 if ( failFast && alternatives.empty() ) { 180 181 throw SemanticError( "No reasonable alternatives for expression ", expr ); 181 182 } 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 }187 183 if ( prune ) { 184 auto oldsize = alternatives.size(); 188 185 PRINT( 189 186 std::cerr << "alternatives before prune:" << std::endl; … … 192 189 AltList::iterator oldBegin = alternatives.begin(); 193 190 pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) ); 194 if ( alternatives.begin() == oldBegin ) {191 if ( failFast && alternatives.begin() == oldBegin ) { 195 192 std::ostringstream stream; 196 193 AltList winners; 197 194 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"; 199 196 expr->print( stream ); 200 stream << "Alternatives are: ";201 printAlts( winners, stream, 8);197 stream << "Alternatives are:\n"; 198 printAlts( winners, stream, 1 ); 202 199 throw SemanticError( stream.str() ); 203 200 } 204 201 alternatives.erase( oldBegin, alternatives.end() ); 202 PRINT( 203 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl; 204 ) 205 205 PRINT( 206 206 std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl; 207 207 ) 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 } 208 214 } 209 215 … … 215 221 } 216 222 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 ); 219 233 } 220 234 … … 299 313 Cost convCost = conversionCost( actualType, formalType, indexer, env ); 300 314 PRINT( 301 std::cerr << std::endl << "cost is " << convCost << std::endl;315 std::cerr << std::endl << "cost is " << convCost << std::endl; 302 316 ) 303 317 if ( convCost == Cost::infinity ) { … … 305 319 } 306 320 convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) ); 321 PRINT( 322 std::cerr << "cost with polycost is " << convCost << std::endl; 323 ) 307 324 return convCost; 308 325 } … … 310 327 Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) { 311 328 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. 317 333 Cost tmpCost = convCost; 318 334 tmpCost.incPoly( -tmpCost.get_polyCost() ); … … 357 373 if ( function->get_isVarArgs() ) { 358 374 convCost.incUnsafe(); 375 PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; ) 359 376 // convert reference-typed expressions to value-typed expressions 360 377 referenceToRvalueConversion( *actualExpr ); … … 365 382 } 366 383 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 )376 384 convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env ); 377 385 ++formal; // can't be in for-loop update because of the continue … … 481 489 Alternative newerAlt( newAlt ); 482 490 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() ); 484 492 DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) ); 485 493 … … 507 515 std::cerr << std::endl; 508 516 ) 509 ApplicationExpr *appExpr = static_cast< ApplicationExpr* >( newerAlt.expr );510 517 // 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(); 512 519 for ( UniqueId id : cur->second.idChain ) { 513 520 inferParameters = (*inferParameters)[ id ].inferParams.get(); … … 574 581 std::vector<unsigned> tupleEls; /// Number of elements in current tuple element(s) 575 582 576 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 583 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 577 584 const OpenVarSet& openVars) 578 585 : actuals(), env(env), need(need), have(have), openVars(openVars), nextArg(0), 579 586 expls(), nextExpl(0), tupleEls() {} 580 587 581 588 /// Starts a new tuple expression 582 589 void beginTuple() { … … 613 620 614 621 /// 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, 618 625 const SymTab::Indexer& indexer ) { 619 626 if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) { … … 622 629 for ( Type* type : *tupleType ) { 623 630 // 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 ) ) 625 632 return false; 626 633 } … … 651 658 Type* argType = result.actuals.back().expr->get_result(); 652 659 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 654 661 // argument forwarding purposes 655 662 // 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 657 664 // types flattened both before unifying lists? then pass in TupleType 658 665 // (ttype) below. … … 664 671 } 665 672 // 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, 667 674 result.openVars, indexer ) ) { 668 675 finalResults.push_back( std::move(result) ); … … 677 684 aResult.env.addActual( actual.env, aResult.openVars ); 678 685 Cost cost = actual.cost; 679 686 680 687 // explode argument 681 688 std::vector<Alternative> exploded; 682 689 Tuples::explode( actual, indexer, back_inserter( exploded ) ); 683 690 684 691 // add exploded argument to tuple 685 692 for ( Alternative& aActual : exploded ) { … … 699 706 return ! results.empty(); 700 707 } 701 708 702 709 // iterate each current subresult 703 710 for ( unsigned iResult = 0; iResult < results.size(); ++iResult ) { … … 717 724 std::cerr << std::endl; 718 725 ) 719 720 if ( unify( formalType, actualType, result.env, result.need, result.have, 726 727 if ( unify( formalType, actualType, result.env, result.need, result.have, 721 728 result.openVars, indexer ) ) { 722 729 ++result.nextExpl; … … 729 736 if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) { 730 737 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, 732 739 result.have, result.openVars, indexer ) ) { 733 740 nextResults.push_back( std::move(result.withArg( cnstExpr )) ); … … 784 791 results.swap( nextResults ); 785 792 nextResults.clear(); 786 793 787 794 return ! results.empty(); 788 795 } 789 796 790 797 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, 793 800 OutputIterator out ) { 794 801 OpenVarSet funcOpenVars; 795 802 AssertionSet funcNeed, funcHave; 796 TypeEnvironment funcEnv ;803 TypeEnvironment funcEnv( func.env ); 797 804 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 799 806 // list are still considered open. 800 807 funcEnv.add( funcType->get_forall() ); … … 802 809 if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) { 803 810 // 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, 806 813 indexer ) ) { 807 814 // unification failed, don't pursue this function alternative … … 815 822 for ( DeclarationWithType* formal : funcType->get_parameters() ) { 816 823 ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal ); 817 if ( ! instantiateArgument( 824 if ( ! instantiateArgument( 818 825 obj->get_type(), obj->get_init(), args, results, nextResults, indexer ) ) 819 826 return; … … 897 904 898 905 std::vector< AlternativeFinder > argAlternatives; 899 findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), 906 findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), 900 907 back_inserter( argAlternatives ) ); 901 908 … … 905 912 906 913 // find function operators 914 static NameExpr *opExpr = new NameExpr( "?()" ); 907 915 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); 914 918 PRINT( 915 919 std::cerr << "known function ops:" << std::endl; 916 printAlts( funcOpFinder.alternatives, std::cerr, 8);920 printAlts( funcOpFinder.alternatives, std::cerr, 1 ); 917 921 ) 918 922 … … 930 934 Alternative newFunc( *func ); 931 935 referenceToRvalueConversion( newFunc.expr ); 932 makeFunctionAlternatives( newFunc, function, argAlternatives, 936 makeFunctionAlternatives( newFunc, function, argAlternatives, 933 937 std::back_inserter( candidates ) ); 934 938 } … … 939 943 Alternative newFunc( *func ); 940 944 referenceToRvalueConversion( newFunc.expr ); 941 makeFunctionAlternatives( newFunc, function, argAlternatives, 945 makeFunctionAlternatives( newFunc, function, argAlternatives, 942 946 std::back_inserter( candidates ) ); 943 947 } // if 944 948 } // if 945 } 949 } 946 950 } catch ( SemanticError &e ) { 947 951 errors.append( e ); … … 958 962 try { 959 963 // check if type is a pointer to function 960 if ( PointerType* pointer = dynamic_cast<PointerType*>( 964 if ( PointerType* pointer = dynamic_cast<PointerType*>( 961 965 funcOp->expr->get_result()->stripReferences() ) ) { 962 if ( FunctionType* function = 966 if ( FunctionType* function = 963 967 dynamic_cast<FunctionType*>( pointer->get_base() ) ) { 964 968 Alternative newFunc( *funcOp ); 965 969 referenceToRvalueConversion( newFunc.expr ); 966 makeFunctionAlternatives( newFunc, function, argAlternatives, 970 makeFunctionAlternatives( newFunc, function, argAlternatives, 967 971 std::back_inserter( candidates ) ); 968 972 } … … 1003 1007 candidates.splice( candidates.end(), alternatives ); 1004 1008 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 ) ); 1006 1012 1007 1013 // function may return struct or union value, in which case we need to add alternatives for implicit 1008 1014 // conversions to each of the anonymous members, must happen after findMinCost since anon conversions 1009 1015 // are never the cheapest expression 1010 for ( const Alternative & alt : alternatives ) {1016 for ( const Alternative & alt : winners ) { 1011 1017 addAnonConversions( alt ); 1012 1018 } 1019 alternatives.splice( alternatives.begin(), winners ); 1013 1020 1014 1021 if ( alternatives.empty() && targetType && ! targetType->isVoid() ) { … … 1028 1035 bool isLvalue( Expression *expr ) { 1029 1036 // 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() ) ); 1031 1038 } 1032 1039 … … 1103 1110 thisCost.incSafe( discardedValues ); 1104 1111 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 ) ); 1110 1113 } // if 1111 1114 } // for … … 1123 1126 AlternativeFinder finder( indexer, env ); 1124 1127 // 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() ); 1127 1129 for ( Alternative & alt : finder.alternatives ) { 1128 1130 alternatives.push_back( Alternative( … … 1163 1165 PRINT( std::cerr << "nameExpr is " << nameExpr->get_name() << std::endl; ) 1164 1166 for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) { 1165 VariableExpr newExpr( *i , nameExpr->get_argName());1167 VariableExpr newExpr( *i ); 1166 1168 alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) ); 1167 1169 PRINT( … … 1398 1400 findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), back_inserter( subExprAlternatives ) ); 1399 1401 std::list< AltList > possibilities; 1400 // TODO re-write to use iterative method1401 1402 combos( subExprAlternatives.begin(), subExprAlternatives.end(), back_inserter( possibilities ) ); 1402 1403 for ( std::list< AltList >::const_iterator i = possibilities.begin(); i != possibilities.end(); ++i ) { … … 1422 1423 // don't prune here, since it's guaranteed all alternatives will have the same type 1423 1424 // (giving the alternatives different types is half of the point of ConstructorExpr nodes) 1424 finder.findWith Adjustment( ctorExpr->get_callExpr(), false);1425 finder.findWithoutPrune( ctorExpr->get_callExpr() ); 1425 1426 for ( Alternative & alt : finder.alternatives ) { 1426 1427 alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) ); … … 1459 1460 // O(N^2) checks of d-types with e-types 1460 1461 for ( InitAlternative & initAlt : initExpr->get_initAlts() ) { 1461 Type * toType = resolveTypeof( initAlt.type , indexer );1462 Type * toType = resolveTypeof( initAlt.type->clone(), indexer ); 1462 1463 SymTab::validateType( toType, &indexer ); 1463 1464 adjustExprType( toType, env, indexer ); … … 1488 1489 // count one safe conversion for each value that is thrown away 1489 1490 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 ) ); 1491 1493 } 1492 1494 }
Note: See TracChangeset
for help on using the changeset viewer.