Changeset aeb75b1 for src/ResolvExpr/AlternativeFinder.cc
 Timestamp:
 Oct 2, 2017, 3:02:21 PM (4 years ago)
 Branches:
 aaronthesis, armeh, cleanupdtors, deferred_resn, demangler, jacob/cs343translation, jenkinssandbox, master, newast, newastuniqueexpr, newenv, no_list, persistentindexer, resolvnew, with_gc
 Children:
 e472d54
 Parents:
 9bae71f
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

src/ResolvExpr/AlternativeFinder.cc
r9bae71f raeb75b1 22 22 #include <memory> // for allocator_traits<>::value_type 23 23 #include <utility> // for pair 24 #include <vector> // for vector 24 25 25 26 #include "Alternative.h" // for AltList, Alternative … … 396 397 /// needAssertions.insert( needAssertions.end(), (*tyvar)>get_assertions().begin(), (*tyvar)>get_assertions().end() ); 397 398 } 398 }399 400 /// instantiate a single argument by matching actuals from [actualIt, actualEnd) against formalType,401 /// producing expression(s) in out and their total cost in cost.402 template< typename AltIterator, typename OutputIterator >403 bool instantiateArgument( Type * formalType, Initializer * defaultValue, AltIterator & actualIt, AltIterator actualEnd, OpenVarSet & openVars, TypeEnvironment & resultEnv, AssertionSet & resultNeed, AssertionSet & resultHave, const SymTab::Indexer & indexer, Cost & cost, OutputIterator out ) {404 if ( TupleType * tupleType = dynamic_cast< TupleType * >( formalType ) ) {405 // formalType is a TupleType  group actuals into a TupleExpr whose type unifies with the TupleType406 std::list< Expression * > exprs;407 for ( Type * type : *tupleType ) {408 if ( ! instantiateArgument( type, defaultValue, actualIt, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( exprs ) ) ) {409 deleteAll( exprs );410 return false;411 }412 }413 *out++ = new TupleExpr( exprs );414 } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {415 // xxx  mixing default arguments with variadic??416 std::list< Expression * > exprs;417 for ( ; actualIt != actualEnd; ++actualIt ) {418 exprs.push_back( actualIt>expr>clone() );419 cost += actualIt>cost;420 }421 Expression * arg = nullptr;422 if ( exprs.size() == 1 && Tuples::isTtype( exprs.front()>get_result() ) ) {423 // the case where a ttype value is passed directly is special, e.g. for argument forwarding purposes424 // xxx  what if passing multiple arguments, last of which is ttype?425 // xxx  what would happen if unify was changed so that unifying tuple types flattened both before unifying lists? then pass in TupleType(ttype) below.426 arg = exprs.front();427 } else {428 arg = new TupleExpr( exprs );429 }430 assert( arg && arg>get_result() );431 if ( ! unify( ttype, arg>get_result(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {432 return false;433 }434 *out++ = arg;435 } else if ( actualIt != actualEnd ) {436 // both actualType and formalType are atomic (nontuple) types  if they unify437 // then accept actual as an argument, otherwise return false (fail to instantiate argument)438 Expression * actual = actualIt>expr;439 Type * actualType = actual>get_result();440 441 PRINT(442 std::cerr << "formal type is ";443 formalType>print( std::cerr );444 std::cerr << std::endl << "actual type is ";445 actualType>print( std::cerr );446 std::cerr << std::endl;447 )448 if ( ! unify( formalType, actualType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {449 // std::cerr << "unify failed" << std::endl;450 return false;451 }452 // move the expression from the alternative to the output iterator453 *out++ = actual;454 actualIt>expr = nullptr;455 cost += actualIt>cost;456 ++actualIt;457 } else {458 // End of actuals  Handle default values459 if ( SingleInit *si = dynamic_cast<SingleInit *>( defaultValue )) {460 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( si>get_value() ) ) {461 // so far, only constant expressions are accepted as default values462 if ( ConstantExpr *cnstexpr = dynamic_cast<ConstantExpr *>( castExpr>get_arg() ) ) {463 if ( Constant *cnst = dynamic_cast<Constant *>( cnstexpr>get_constant() ) ) {464 if ( unify( formalType, cnst>get_type(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {465 *out++ = cnstexpr>clone();466 return true;467 } // if468 } // if469 } // if470 }471 } // if472 return false;473 } // if474 return true;475 }476 477 bool AlternativeFinder::instantiateFunction( std::list< DeclarationWithType* >& formals, const AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave, AltList & out ) {478 simpleCombineEnvironments( actuals.begin(), actuals.end(), resultEnv );479 // make sure we don't widen any existing bindings480 for ( TypeEnvironment::iterator i = resultEnv.begin(); i != resultEnv.end(); ++i ) {481 i>allowWidening = false;482 }483 resultEnv.extractOpenVars( openVars );484 485 // flatten actuals so that each actual has an atomic (nontuple) type486 AltList exploded;487 Tuples::explode( actuals, indexer, back_inserter( exploded ) );488 489 AltList::iterator actualExpr = exploded.begin();490 AltList::iterator actualEnd = exploded.end();491 for ( DeclarationWithType * formal : formals ) {492 // match flattened actuals with formal parameters  actuals will be grouped to match493 // with formals as appropriate494 Cost cost = Cost::zero;495 std::list< Expression * > newExprs;496 ObjectDecl * obj = strict_dynamic_cast< ObjectDecl * >( formal );497 if ( ! instantiateArgument( obj>get_type(), obj>get_init(), actualExpr, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( newExprs ) ) ) {498 deleteAll( newExprs );499 return false;500 }501 // success  produce argument as a new alternative502 assert( newExprs.size() == 1 );503 out.push_back( Alternative( newExprs.front(), resultEnv, cost ) );504 }505 if ( actualExpr != actualEnd ) {506 // there are still actuals remaining, but we've run out of formal parameters to match against507 // this is okay only if the function is variadic508 if ( ! isVarArgs ) {509 return false;510 }511 out.splice( out.end(), exploded, actualExpr, actualEnd );512 }513 return true;514 399 } 515 400 … … 667 552 } 668 553 669 template< typename OutputIterator > 670 void AlternativeFinder::makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const AltList &actualAlt, OutputIterator out ) { 671 OpenVarSet openVars; 672 AssertionSet resultNeed, resultHave; 673 TypeEnvironment resultEnv; 674 makeUnifiableVars( funcType, openVars, resultNeed ); 675 resultEnv.add( funcType>get_forall() ); // add all type variables as open variables now so that those not used in the parameter list are still considered open 676 AltList instantiatedActuals; // filled by instantiate function 554 /// Gets a default value from an initializer, nullptr if not present 555 ConstantExpr* getDefaultValue( Initializer* init ) { 556 if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) { 557 if ( CastExpr* ce = dynamic_cast<CastExpr*>( si>get_value() ) ) { 558 return dynamic_cast<ConstantExpr*>( ce>get_arg() ); 559 } 560 } 561 return nullptr; 562 } 563 564 /// State to iteratively build a match of parameter expressions to arguments 565 struct ArgPack { 566 AltList actuals; ///< Arguments included in this pack 567 TypeEnvironment env; ///< Environment for this pack 568 AssertionSet need; ///< Assertions outstanding for this pack 569 AssertionSet have; ///< Assertions found for this pack 570 OpenVarSet openVars; ///< Open variables for this pack 571 unsigned nextArg; ///< Index of next argument in arguments list 572 573 /// Number of elements included in current tuple element (nested appropriately) 574 std::vector<unsigned> tupleEls; 575 576 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 577 const OpenVarSet& openVars) 578 : actuals(), env(env), need(need), have(have), openVars(openVars), nextArg(0), 579 tupleEls() {} 580 581 ArgPack(const ArgPack& old, Expression* actual, const Cost& cost = Cost::zero) 582 : actuals(old.actuals), env(old.env), need(old.need), have(old.have), 583 openVars(old.openVars), nextArg(old.nextArg + 1), tupleEls(old.tupleEls) { 584 actuals.emplace_back( actual, this>env, cost ); 585 } 586 587 ArgPack(const ArgPack& old, Expression* actual, TypeEnvironment&& env, AssertionSet&& need, 588 AssertionSet&& have, const Cost& cost = Cost::zero) 589 : actuals(old.actuals), env(std::move(env)), need(std::move(need)), 590 have(std::move(have)), openVars(old.openVars), nextArg(old.nextArg + 1), 591 tupleEls(old.tupleEls) { 592 // add new actual 593 actuals.emplace_back( actual, this>env, cost ); 594 // count tuple elements, if applicable 595 if ( ! tupleEls.empty() ) ++tupleEls.back(); 596 } 597 598 /// Starts a new tuple expression 599 void beginTuple() { 600 if ( ! tupleEls.empty() ) ++tupleEls.back(); 601 tupleEls.push_back(0); 602 } 603 604 /// Ends a tuple expression, consolidating the appropriate actuals 605 void endTuple() { 606 // set up new Tuple alternative 607 std::list<Expression*> exprs; 608 Cost cost = Cost::zero; 609 610 // transfer elements into alternative 611 for (unsigned i = 0; i < tupleEls.back(); ++i) { 612 exprs.push_front( actuals.back().expr ); 613 cost += actuals.back().cost; 614 actuals.pop_back(); 615 } 616 tupleEls.pop_back(); 617 618 // build new alternative 619 actuals.emplace_back( new TupleExpr( exprs ), this>env, cost ); 620 } 621 }; 622 623 /// Iterates a result, exploding actuals as needed. 624 /// add is a function that takes the same parameters as this (with the exception of add) 625 template<typename F> 626 void addExplodedActual( ArgPack& result, Expression* expr, Cost cost, 627 std::vector<ArgPack>& nextResults, F add ) { 628 Type* res = expr>get_result()>stripReferences(); 629 if ( TupleType* tupleType = dynamic_cast<TupleType*>( res ) ) { 630 if ( TupleExpr* tupleExpr = dynamic_cast<TupleExpr*>( expr ) ) { 631 // recursively explode tuple 632 for ( Expression* sexpr : tupleExpr>get_exprs() ) { 633 addExplodedActual( result, sexpr, cost, nextResults, add ); 634 cost = Cost::zero; // reset cost so not duplicated 635 } 636 } else { 637 // tuple type, but not tuple expr  recursively index into components. 638 // if expr type is reference, convert to value type 639 Expression* arg = expr>clone(); 640 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 641 // expressions which may contain side effects require a single unique instance of the expression. 642 arg = new UniqueExpr( arg ); 643 } 644 // cast reference to value type to facilitate further explosion 645 if ( dynamic_cast<ReferenceType*>( arg>get_result() ) ) { 646 arg = new CastExpr( arg, tupleType>clone() ); 647 } 648 // explode tuple by index 649 for ( unsigned i = 0; i < tupleType>size(); ++i ) { 650 TupleIndexExpr* idx = new TupleIndexExpr( arg>clone(), i ); 651 addExplodedActual( result, idx, cost, nextResults, add ); 652 cost = Cost::zero; // reset cost so not duplicated 653 delete idx; 654 } 655 delete arg; 656 } 657 } else { 658 // add nontuple results directly 659 add( result, expr>clone(), cost, nextResults ); 660 } 661 } 662 663 /// Instantiates an argument to match a formal, returns false if no results left 664 bool instantiateArgument( Type* formalType, Initializer* initializer, 665 const std::vector< AlternativeFinder >& args, 666 std::vector<ArgPack>& results, std::vector<ArgPack>& nextResults, 667 const SymTab::Indexer& indexer ) { 668 if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) { 669 // formalType is a TupleType  group actuals into a TupleExpr 670 for ( ArgPack& result : results ) { result.beginTuple(); } 671 for ( Type* type : *tupleType ) { 672 // xxx  dropping initializer changes behaviour from previous, but seems correct 673 if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) ) 674 return false; 675 } 676 for ( ArgPack& result : results ) { result.endTuple(); } 677 return true; 678 } else if ( TypeInstType* ttype = Tuples::isTtype( formalType ) ) { 679 // formalType is a ttype, consumes all remaining arguments 680 // xxx  mixing default arguments with variadic?? 681 std::vector<ArgPack> finalResults{}; /// list of completed tuples 682 // start tuples 683 for ( ArgPack& result : results ) { result.beginTuple(); } 684 // iterate until all results completed 685 while ( ! results.empty() ) { 686 // add another argument to results 687 for ( ArgPack& result : results ) { 688 // finish result when out of arguments 689 if ( result.nextArg >= args.size() ) { 690 Type* argType = result.actuals.back().expr>get_result(); 691 if ( result.tupleEls.back() == 1 && Tuples::isTtype( argType ) ) { 692 // the case where a ttype value is passed directly is special, e.g. for 693 // argument forwarding purposes 694 // xxx  what if passing multiple arguments, last of which is ttype? 695 // xxx  what would happen if unify was changed so that unifying tuple 696 // types flattened both before unifying lists? then pass in TupleType 697 // (ttype) below. 698 result.tupleEls.pop_back(); 699 } else { 700 // collapse leftover arguments into tuple 701 result.endTuple(); 702 argType = result.actuals.back().expr>get_result(); 703 } 704 // check unification for ttype before adding to final 705 if ( unify( ttype, argType, result.env, result.need, result.have, 706 result.openVars, indexer ) ) { 707 finalResults.emplace_back( std::move(result) ); 708 } 709 continue; 710 } 711 712 // add each possible next argument 713 for ( const Alternative& actual : args[result.nextArg] ) { 714 addExplodedActual( result, actual.expr, actual.cost, nextResults, 715 []( ArgPack& result, Expression* expr, Cost cost, 716 std::vector<ArgPack>& nextResults ) { 717 nextResults.emplace_back( result, expr, cost ); 718 } ); 719 } 720 } 721 722 // reset for next round 723 results.swap( nextResults ); 724 nextResults.clear(); 725 } 726 results.swap( finalResults ); 727 return ! results.empty(); 728 } 729 730 // iterate each current subresult 731 for ( ArgPack& result : results ) { 732 if ( result.nextArg >= args.size() ) { 733 // If run out of actuals, handle default values 734 if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) { 735 if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr>get_constant() ) ) { 736 TypeEnvironment resultEnv = result.env; 737 AssertionSet resultNeed = result.need, resultHave = result.have; 738 if ( unify( formalType, cnst>get_type(), 739 resultEnv, resultNeed, resultHave, result.openVars, 740 indexer ) ) { 741 nextResults.emplace_back( result, cnstExpr>clone(), 742 std::move(resultEnv), std::move(resultNeed), 743 std::move(resultHave) ); 744 } 745 } 746 } 747 continue; 748 } 749 750 // Check each possible next argument 751 for ( const Alternative& actual : args[result.nextArg] ) { 752 addExplodedActual( result, actual.expr, actual.cost, nextResults, 753 [formalType,&indexer]( ArgPack& result, Expression* expr, Cost cost, 754 std::vector<ArgPack>& nextResults ) { 755 // attempt to unify actual with parameter 756 TypeEnvironment resultEnv = result.env; 757 AssertionSet resultNeed = result.need, resultHave = result.have; 758 Type* actualType = expr>get_result(); 759 760 PRINT( 761 std::cerr << "formal type is "; 762 formalType>print( std::cerr ); 763 std::cerr << std::endl << "actual type is "; 764 actualType>print( std::cerr ); 765 std::cerr << std::endl; 766 ) 767 768 if ( unify( formalType, actualType, resultEnv, resultNeed, resultHave, 769 result.openVars, indexer ) ) { 770 nextResults.emplace_back( result, expr>clone(), 771 std::move(resultEnv), std::move(resultNeed), std::move(resultHave), 772 cost ); 773 } 774 } ); 775 } 776 } 777 778 // reset for next parameter 779 results.swap( nextResults ); 780 nextResults.clear(); 781 782 return ! results.empty(); 783 } 784 785 template<typename OutputIterator> 786 void AlternativeFinder::makeFunctionAlternatives( const Alternative& func, 787 FunctionType* funcType, const std::vector< AlternativeFinder >& args, 788 OutputIterator out ) { 789 OpenVarSet funcOpenVars; 790 AssertionSet funcNeed, funcHave; 791 TypeEnvironment funcEnv; 792 makeUnifiableVars( funcType, funcOpenVars, funcNeed ); 793 // add all type variables as open variables now so that those not used in the parameter 794 // list are still considered open. 795 funcEnv.add( funcType>get_forall() ); 796 677 797 if ( targetType && ! targetType>isVoid() && ! funcType>get_returnVals().empty() ) { 678 798 // attempt to narrow based on expected target type 679 Type * returnType = funcType>get_returnVals().front()>get_type(); 680 if ( ! unify( returnType, targetType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) { 681 // unification failed, don't pursue this alternative 799 Type* returnType = funcType>get_returnVals().front()>get_type(); 800 if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars, 801 indexer ) ) { 802 // unification failed, don't pursue this function alternative 682 803 return; 683 804 } 684 805 } 685 806 686 if ( instantiateFunction( funcType>get_parameters(), actualAlt, funcType>get_isVarArgs(), openVars, resultEnv, resultNeed, resultHave, instantiatedActuals ) ) { 807 // iteratively build matches, one parameter at a time 808 std::vector<ArgPack> results{ ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } }; 809 std::vector<ArgPack> nextResults{}; 810 for ( DeclarationWithType* formal : funcType>get_parameters() ) { 811 ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal ); 812 if ( ! instantiateArgument( 813 obj>get_type(), obj>get_init(), args, results, nextResults, indexer ) ) 814 return; 815 } 816 817 // filter out results that don't use all the arguments, and aren't variadic 818 std::vector<ArgPack> finalResults{}; 819 if ( funcType>get_isVarArgs() ) { 820 while ( ! results.empty() ) { 821 // build combinations for all remaining arguments 822 for ( ArgPack& result : results ) { 823 // keep if used all arguments 824 if ( result.nextArg >= args.size() ) { 825 finalResults.emplace_back( std::move(result) ); 826 continue; 827 } 828 829 // add each possible next argument 830 for ( const Alternative& actual : args[result.nextArg] ) { 831 nextResults.emplace_back( result, actual.expr, actual.cost ); 832 } 833 } 834 835 // reset for next round 836 results.swap( nextResults ); 837 nextResults.clear(); 838 } 839 } else { 840 // filter out results that don't use all the arguments 841 for ( ArgPack& result : results ) { 842 if ( result.nextArg >= args.size() ) { 843 finalResults.emplace_back( std::move(result) ); 844 } 845 } 846 } 847 848 // validate matching combos, add to final result list 849 for ( ArgPack& result : finalResults ) { 687 850 ApplicationExpr *appExpr = new ApplicationExpr( func.expr>clone() ); 688 Alternative newAlt( appExpr, result Env, sumCost( instantiatedActuals ) );689 makeExprList( instantiatedActuals, appExpr>get_args() );851 Alternative newAlt( appExpr, result.env, sumCost( result.actuals ) ); 852 makeExprList( result.actuals, appExpr>get_args() ); 690 853 PRINT( 691 854 std::cerr << "instantiate function success: " << appExpr << std::endl; 692 855 std::cerr << "need assertions:" << std::endl; 693 printAssertionSet( result Need, std::cerr, 8 );856 printAssertionSet( result.need, std::cerr, 8 ); 694 857 ) 695 inferParameters( result Need, resultHave, newAlt,openVars, out );858 inferParameters( result.need, result.have, newAlt, result.openVars, out ); 696 859 } 697 860 } … … 703 866 if ( funcFinder.alternatives.empty() ) return; 704 867 705 std::list< AlternativeFinder > argAlternatives; 706 findSubExprs( untypedExpr>begin_args(), untypedExpr>end_args(), back_inserter( argAlternatives ) ); 707 708 std::list< AltList > possibilities; 709 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) ); 868 std::vector< AlternativeFinder > argAlternatives; 869 findSubExprs( untypedExpr>begin_args(), untypedExpr>end_args(), 870 back_inserter( argAlternatives ) ); 710 871 711 872 // take care of possible tuple assignments 712 873 // if not tuple assignment, assignment is taken care of as a normal function call 713 714 874 /*FIX Tuples::handleTupleAssignment( *this, untypedExpr, possibilities ); 875 */ 715 876 // find function operators 716 877 AlternativeFinder funcOpFinder( indexer, env ); … … 739 900 Alternative newFunc( *func ); 740 901 referenceToRvalueConversion( newFunc.expr ); 741 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) { 742 // XXX 743 //Designators::check_alternative( function, *actualAlt ); 744 makeFunctionAlternatives( newFunc, function, *actualAlt, std::back_inserter( candidates ) ); 745 } 902 makeFunctionAlternatives( newFunc, function, argAlternatives, 903 std::back_inserter( candidates ) ); 746 904 } 747 905 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func>expr>get_result()>stripReferences() ) ) { // handle ftype (e.g. *? on function pointer) … … 751 909 Alternative newFunc( *func ); 752 910 referenceToRvalueConversion( newFunc.expr ); 753 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) { 754 makeFunctionAlternatives( newFunc, function, *actualAlt, std::back_inserter( candidates ) ); 755 } // for 911 makeFunctionAlternatives( newFunc, function, argAlternatives, 912 std::back_inserter( candidates ) ); 756 913 } // if 757 914 } // if 758 } 759 760 // try each function operator ?() with the current function alternative and each of the argument combinations 761 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); funcOp != funcOpFinder.alternatives.end(); ++funcOp ) { 762 // check if the type is pointer to function 763 if ( PointerType *pointer = dynamic_cast< PointerType* >( funcOp>expr>get_result()>stripReferences() ) ) { 764 if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer>get_base() ) ) { 915 } 916 } catch ( SemanticError &e ) { 917 errors.append( e ); 918 } 919 } // for 920 921 // try each function operator ?() with each function alternative 922 if ( ! funcOpFinder.alternatives.empty() ) { 923 // add function alternatives to front of argument list 924 argAlternatives.insert( argAlternatives.begin(), std::move(funcFinder) ); 925 926 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); 927 funcOp != funcOpFinder.alternatives.end(); ++funcOp ) { 928 try { 929 // check if type is a pointer to function 930 if ( PointerType* pointer = dynamic_cast<PointerType*>( 931 funcOp>expr>get_result()>stripReferences() ) ) { 932 if ( FunctionType* function = 933 dynamic_cast<FunctionType*>( pointer>get_base() ) ) { 765 934 Alternative newFunc( *funcOp ); 766 935 referenceToRvalueConversion( newFunc.expr ); 767 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) { 768 AltList currentAlt; 769 currentAlt.push_back( *func ); 770 currentAlt.insert( currentAlt.end(), actualAlt>begin(), actualAlt>end() ); 771 makeFunctionAlternatives( newFunc, function, currentAlt, std::back_inserter( candidates ) ); 772 } // for 773 } // if 774 } // if 775 } // for 776 } catch ( SemanticError &e ) { 777 errors.append( e ); 778 } 779 } // for 936 makeFunctionAlternatives( newFunc, function, argAlternatives, 937 std::back_inserter( candidates ) ); 938 } 939 } 940 } catch ( SemanticError &e ) { 941 errors.append( e ); 942 } 943 } 944 } 780 945 781 946 // Implement SFINAE; resolution errors are only errors if there aren't any nonerroneous resolutions
Note: See TracChangeset
for help on using the changeset viewer.