- File:
-
- 1 edited
-
src/ResolvExpr/CandidateFinder.cpp (modified) (92 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CandidateFinder.cpp
ref9988b r18e683b 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A ndrew Beach12 // Last Modified On : Tue Oct 1 14:55:00 201913 // Update Count : 211 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Wed Jun 5 14:30:00 2019 13 // Update Count : 1 14 14 // 15 15 … … 54 54 return new ast::CastExpr{ expr, expr->result->stripReferences() }; 55 55 } 56 56 57 57 return expr; 58 58 } … … 61 61 UniqueId globalResnSlot = 0; 62 62 63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,65 const ast:: SymbolTable & symtab, const ast::TypeEnvironment & env63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab, 65 const ast::TypeEnvironment & env 66 66 ) { 67 67 PRINT( … … 74 74 std::cerr << std::endl; 75 75 ) 76 Cost convCost = conversionCost( argType, paramType, argIsLvalue,symtab, env );76 Cost convCost = conversionCost( argType, paramType, symtab, env ); 77 77 PRINT( 78 78 std::cerr << std::endl << "cost is " << convCost << std::endl; … … 107 107 108 108 /// Computes conversion cost for a given expression to a given type 109 const ast::Expr * computeExpressionConversionCost( 110 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 111 111 ) { 112 Cost convCost = computeConversionCost( 113 arg->result, paramType, arg->get_lvalue(), symtab, env ); 112 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env ); 114 113 outCost += convCost; 115 114 116 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 117 // 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 118 117 // infer parameters and this does not currently work for the reason stated below 119 118 Cost tmpCost = convCost; … … 124 123 return new ast::CastExpr{ arg, newType }; 125 124 126 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 127 // 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, 128 127 // once this is fixed it should be possible to resolve the cast. 129 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 130 // 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 131 130 // commontype(zero_t, DT*) is DT*, rather than nothing 132 131 133 132 // CandidateFinder finder{ symtab, env }; 134 133 // finder.find( arg, ResolvMode::withAdjustment() ); 135 // assertf( finder.candidates.size() > 0, 134 // assertf( finder.candidates.size() > 0, 136 135 // "Somehow castable expression failed to find alternatives." ); 137 // assertf( finder.candidates.size() == 1, 136 // assertf( finder.candidates.size() == 1, 138 137 // "Somehow got multiple alternatives for known cast expression." ); 139 138 // return finder.candidates.front()->expr; … … 144 143 145 144 /// Computes conversion cost for a given candidate 146 Cost computeApplicationConversionCost( 147 CandidateRef cand, const ast::SymbolTable & symtab 145 Cost computeApplicationConversionCost( 146 CandidateRef cand, const ast::SymbolTable & symtab 148 147 ) { 149 148 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); … … 168 167 if ( function->isVarArgs ) { 169 168 convCost.incUnsafe(); 170 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 169 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 171 170 << convCost << std::endl; ; ) 172 171 // convert reference-typed expressions into value-typed expressions 173 cand->expr = ast::mutate_field_index( 174 appExpr, &ast::ApplicationExpr::args, i, 172 cand->expr = ast::mutate_field_index( 173 appExpr, &ast::ApplicationExpr::args, i, 175 174 referenceToRvalueConversion( args[i], convCost ) ); 176 175 continue; … … 181 180 // Default arguments should be free - don't include conversion cost. 182 181 // Unwrap them here because they are not relevant to the rest of the system 183 cand->expr = ast::mutate_field_index( 182 cand->expr = ast::mutate_field_index( 184 183 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 185 184 ++param; … … 189 188 // mark conversion cost and also specialization cost of param type 190 189 const ast::Type * paramType = (*param)->get_type(); 191 cand->expr = ast::mutate_field_index( 192 appExpr, &ast::ApplicationExpr::args, i, 193 computeExpressionConversionCost( 190 cand->expr = ast::mutate_field_index( 191 appExpr, &ast::ApplicationExpr::args, i, 192 computeExpressionConversionCost( 194 193 args[i], paramType, symtab, cand->env, convCost ) ); 195 194 convCost.decSpec( specCost( paramType ) ); … … 199 198 if ( param != params.end() ) return Cost::infinity; 200 199 201 // 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 202 201 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 203 202 // … … 216 215 } 217 216 218 void makeUnifiableVars( 219 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 220 ast::AssertionSet & need 217 void makeUnifiableVars( 218 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 219 ast::AssertionSet & need 221 220 ) { 222 221 for ( const ast::TypeDecl * tyvar : type->forall ) { … … 255 254 256 255 ArgPack() 257 : 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 ), 258 257 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 259 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 260 265 ArgPack( 261 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 262 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 263 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 264 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 265 266 ArgPack( 267 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 268 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 269 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, 270 269 unsigned nextExpl = 0, unsigned explAlt = 0 ) 271 270 : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ), 272 271 have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 273 272 nextExpl( nextExpl ), explAlt( explAlt ) {} 274 273 275 274 ArgPack( 276 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 275 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 277 276 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 278 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 279 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 ), 280 279 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 281 280 282 281 /// true if this pack is in the middle of an exploded argument 283 282 bool hasExpl() const { return nextExpl > 0; } … … 287 286 return args[ nextArg-1 ][ explAlt ]; 288 287 } 289 288 290 289 /// Ends a tuple expression, consolidating the appropriate args 291 290 void endTuple( const std::vector< ArgPack > & packs ) { … … 308 307 309 308 /// Instantiates an argument to match a parameter, returns false if no matching results left 310 bool instantiateArgument( 311 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 312 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 313 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 314 313 ) { 315 314 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { … … 319 318 // xxx - dropping initializer changes behaviour from previous, but seems correct 320 319 // ^^^ need to handle the case where a tuple has a default argument 321 if ( ! instantiateArgument( 320 if ( ! instantiateArgument( 322 321 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 323 322 nTuples = 0; … … 330 329 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 331 330 // paramType is a ttype, consumes all remaining arguments 332 331 333 332 // completed tuples; will be spliced to end of results to finish 334 333 std::vector< ArgPack > finalResults{}; … … 343 342 for ( std::size_t i = genStart; i < genEnd; ++i ) { 344 343 unsigned nextArg = results[i].nextArg; 345 344 346 345 // use next element of exploded tuple if present 347 346 if ( results[i].hasExpl() ) { … … 353 352 results.emplace_back( 354 353 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 355 copy( results[i].need ), copy( results[i].have ), 354 copy( results[i].need ), copy( results[i].have ), 356 355 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 357 356 results[i].explAlt ); … … 371 370 // push empty tuple expression 372 371 newResult.parent = i; 373 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} }; 372 std::vector< ast::ptr< ast::Expr > > emptyList; 373 newResult.expr = 374 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) }; 374 375 argType = newResult.expr->result; 375 376 } else { … … 399 400 400 401 // check unification for ttype before adding to final 401 if ( 402 unify( 402 if ( 403 unify( 403 404 ttype, argType, newResult.env, newResult.need, newResult.have, 404 newResult.open, symtab ) 405 newResult.open, symtab ) 405 406 ) { 406 407 finalResults.emplace_back( move( newResult ) ); … … 423 424 if ( expl.exprs.empty() ) { 424 425 results.emplace_back( 425 results[i], move( env ), copy( results[i].need ), 426 results[i], move( env ), copy( results[i].need ), 426 427 copy( results[i].have ), move( open ), nextArg + 1, expl.cost ); 427 428 428 429 continue; 429 430 } … … 431 432 // add new result 432 433 results.emplace_back( 433 i, expl.exprs.front(), move( env ), copy( results[i].need ), 434 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, 435 436 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 436 437 } … … 478 479 479 480 results.emplace_back( 480 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 481 482 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 482 483 } … … 494 495 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 495 496 results.emplace_back( 496 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 497 498 move( need ), move( have ), move( open ), nextArg, nTuples ); 498 499 } … … 516 517 if ( expl.exprs.empty() ) { 517 518 results.emplace_back( 518 results[i], move( env ), move( need ), move( have ), move( open ), 519 results[i], move( env ), move( need ), move( have ), move( open ), 519 520 nextArg + 1, expl.cost ); 520 521 521 522 continue; 522 523 } … … 538 539 // add new result 539 540 results.emplace_back( 540 i, expr, move( env ), move( need ), move( have ), move( open ), 541 i, expr, move( env ), move( need ), move( have ), move( open ), 541 542 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 542 543 } … … 547 548 genStart = genEnd; 548 549 549 return genEnd != results.size(); // were any new results added?550 return genEnd != results.size(); 550 551 } 551 552 552 553 /// Generate a cast expression from `arg` to `toType` 553 const ast::Expr * restructureCast( 554 const ast::Expr * restructureCast( 554 555 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 555 556 ) { 556 if ( 557 arg->result->size() > 1 558 && ! toType->isVoid() 559 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 560 561 ) { 561 // Argument is a tuple and the target type is neither void nor a reference. Cast each 562 // member of the tuple to its corresponding target type, producing the tuple of those 563 // cast expressions. If there are more components of the tuple than components in the 564 // 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 565 566 // UniqueExpr ensures that the side effects will still be produced) 566 567 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 567 // 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 568 569 // the expression 569 570 arg = new ast::UniqueExpr{ arg->location, arg }; … … 573 574 // cast each component 574 575 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 575 components.emplace_back( 576 components.emplace_back( 576 577 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 577 578 } … … 593 594 594 595 /// Actually visits expressions to find their candidate interpretations 595 class Finder final : public ast::WithShortCircuiting { 596 struct Finder final : public ast::WithShortCircuiting { 597 CandidateFinder & selfFinder; 596 598 const ast::SymbolTable & symtab; 597 public:598 static size_t traceId;599 CandidateFinder & selfFinder;600 599 CandidateList & candidates; 601 600 const ast::TypeEnvironment & tenv; 602 601 ast::ptr< ast::Type > & targetType; 603 602 604 enum Errors {605 NotFound,606 NoMatch,607 ArgsToFew,608 ArgsToMany,609 RetsToFew,610 RetsToMany,611 NoReason612 };613 614 struct {615 Errors code = NotFound;616 } reason;617 618 603 Finder( CandidateFinder & f ) 619 : s ymtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),604 : selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ), 620 605 targetType( f.targetType ) {} 621 606 622 607 void previsit( const ast::Node * ) { visit_children = false; } 623 608 … … 626 611 void addCandidate( Args &&... args ) { 627 612 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 628 reason.code = NoReason;629 613 } 630 614 … … 655 639 656 640 /// Completes a function candidate with arguments located 657 void validateFunctionCandidate( 658 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 659 CandidateList & out 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 660 644 ) { 661 ast::ApplicationExpr * appExpr = 645 ast::ApplicationExpr * appExpr = 662 646 new ast::ApplicationExpr{ func->expr->location, func->expr }; 663 647 // sum cost and accumulate arguments … … 673 657 appExpr->args = move( vargs ); 674 658 // build and validate new candidate 675 auto newCand = 659 auto newCand = 676 660 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 677 661 PRINT( … … 685 669 /// Builds a list of candidates for a function, storing them in out 686 670 void makeFunctionCandidates( 687 const CandidateRef & func, const ast::FunctionType * funcType, 671 const CandidateRef & func, const ast::FunctionType * funcType, 688 672 const ExplodedArgs_new & args, CandidateList & out 689 673 ) { … … 692 676 ast::TypeEnvironment funcEnv{ func->env }; 693 677 makeUnifiableVars( funcType, funcOpen, funcNeed ); 694 // add all type variables as open variables now so that those not used in the 695 // parameterlist are still considered open678 // add all type variables as open variables now so that those not used in the parameter 679 // list are still considered open 696 680 funcEnv.add( funcType->forall ); 697 681 … … 699 683 // attempt to narrow based on expected target type 700 684 const ast::Type * returnType = funcType->returns.front()->get_type(); 701 if ( ! unify( 702 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 685 if ( ! unify( 686 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 703 687 ) { 704 688 // unification failed, do not pursue this candidate … … 714 698 for ( const ast::DeclWithType * param : funcType->params ) { 715 699 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param ); 716 // Try adding the arguments corresponding to the current parameter to the existing 700 // Try adding the arguments corresponding to the current parameter to the existing 717 701 // matches 718 if ( ! instantiateArgument( 702 if ( ! instantiateArgument( 719 703 obj->type, obj->init, args, results, genStart, symtab ) ) return; 720 704 } … … 766 750 if ( expl.exprs.empty() ) { 767 751 results.emplace_back( 768 results[i], move( env ), copy( results[i].need ), 769 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, 770 754 expl.cost ); 771 755 … … 776 760 results.emplace_back( 777 761 i, expl.exprs.front(), move( env ), copy( results[i].need ), 778 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 762 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 779 763 expl.exprs.size() == 1 ? 0 : 1, j ); 780 764 } … … 796 780 /// Adds implicit struct-conversions to the alternative list 797 781 void addAnonConversions( const CandidateRef & cand ) { 798 // adds anonymous member interpretations whenever an aggregate value type is seen. 799 // 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 800 784 // base type to treat the aggregate as the referenced value 801 785 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 802 786 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 803 787 cand->env.apply( aggrType ); 804 788 805 789 if ( aggrType.as< ast::ReferenceType >() ) { 806 790 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; … … 815 799 816 800 /// Adds aggregate member interpretations 817 void addAggMembers( 818 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 819 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 820 804 ) { 821 805 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 822 806 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 823 CandidateRef newCand = std::make_shared<Candidate>( 807 CandidateRef newCand = std::make_shared<Candidate>( 824 808 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 825 // add anonymous member interpretations whenever an aggregate value type is seen 809 // add anonymous member interpretations whenever an aggregate value type is seen 826 810 // as a member expression 827 811 addAnonConversions( newCand ); … … 831 815 832 816 /// Adds tuple member interpretations 833 void addTupleMembers( 834 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 835 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 836 820 ) { 837 821 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 838 // 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 839 823 // length of the tuple to have meaning 840 824 long long val = constantExpr->intValue(); 841 825 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 842 826 addCandidate( 843 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 827 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 844 828 addedCost ); 845 829 } … … 853 837 if ( funcFinder.candidates.empty() ) return; 854 838 855 reason.code = NoMatch; 856 857 std::vector< CandidateFinder > argCandidates = 839 std::vector< CandidateFinder > argCandidates = 858 840 selfFinder.findSubExprs( untypedExpr->args ); 859 841 860 842 // take care of possible tuple assignments 861 843 // if not tuple assignment, handled as normal function call … … 895 877 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 896 878 CandidateRef newFunc{ new Candidate{ *func } }; 897 newFunc->expr = 879 newFunc->expr = 898 880 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 899 881 makeFunctionCandidates( newFunc, function, argExpansions, found ); 900 882 } 901 } else if ( 902 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 883 } else if ( 884 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 903 885 ) { 904 886 if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) { 905 887 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 906 888 CandidateRef newFunc{ new Candidate{ *func } }; 907 newFunc->expr = 889 newFunc->expr = 908 890 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 909 891 makeFunctionCandidates( newFunc, function, argExpansions, found ); … … 919 901 std::vector< ExplodedArg > funcE; 920 902 funcE.reserve( funcFinder.candidates.size() ); 921 for ( const CandidateRef & func : funcFinder ) { 903 for ( const CandidateRef & func : funcFinder ) { 922 904 funcE.emplace_back( *func, symtab ); 923 905 } … … 931 913 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 932 914 CandidateRef newOp{ new Candidate{ *op} }; 933 newOp->expr = 915 newOp->expr = 934 916 referenceToRvalueConversion( newOp->expr, newOp->cost ); 935 917 makeFunctionCandidates( newOp, function, argExpansions, found ); … … 940 922 } 941 923 942 // 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 943 925 // candidates 944 926 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } … … 952 934 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 953 935 auto function = pointer->base.strict_as< ast::FunctionType >(); 954 936 955 937 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 956 938 std::cerr << "parameters are:" << std::endl; … … 975 957 promoteCvtCost( winners ); 976 958 977 // function may return a struct/union value, in which case we need to add candidates 978 // 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 979 961 // `findMinCost`, since anon conversions are never the cheapest 980 962 for ( const CandidateRef & c : winners ) { … … 984 966 985 967 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 986 // 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 987 969 // will sometimes succeed when it wouldn't with a target type binding. 988 970 // For example: … … 1001 983 /// true if expression is an lvalue 1002 984 static bool isLvalue( const ast::Expr * x ) { 1003 return x->result && ( x-> get_lvalue() || x->result.as< ast::ReferenceType >() );985 return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() ); 1004 986 } 1005 987 … … 1007 989 CandidateFinder finder{ symtab, tenv }; 1008 990 finder.find( addressExpr->arg ); 1009 1010 if( finder.candidates.empty() ) return;1011 1012 reason.code = NoMatch;1013 1014 991 for ( CandidateRef & r : finder.candidates ) { 1015 992 if ( ! isLvalue( r->expr ) ) continue; … … 1032 1009 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1033 1010 1034 if( !finder.candidates.empty() ) reason.code = NoMatch;1035 1036 1011 CandidateList matches; 1037 1012 for ( CandidateRef & cand : finder.candidates ) { … … 1041 1016 cand->env.extractOpenVars( open ); 1042 1017 1043 // It is possible that a cast can throw away some values in a multiply-valued 1044 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1045 // 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 1046 1021 // has fewer results than there are types to cast to. 1047 1022 int discardedValues = cand->expr->result->size() - toType->size(); … … 1050 1025 // unification run for side-effects 1051 1026 unify( toType, cand->expr->result, cand->env, need, have, open, symtab ); 1052 Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1053 symtab, cand->env ); 1027 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env ); 1054 1028 PRINT( 1055 1029 std::cerr << "working on cast with result: " << toType << std::endl; … … 1063 1037 // count one safe conversion for each value that is thrown away 1064 1038 thisCost.incSafe( discardedValues ); 1065 CandidateRef newCand = std::make_shared<Candidate>( 1066 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1067 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, 1068 1042 cand->cost + thisCost ); 1069 1043 inferParameters( newCand, matches ); … … 1083 1057 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1084 1058 for ( CandidateRef & r : finder.candidates ) { 1085 addCandidate( 1086 *r, 1059 addCandidate( 1060 *r, 1087 1061 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1088 1062 } … … 1093 1067 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1094 1068 for ( CandidateRef & agg : aggFinder.candidates ) { 1095 // 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 1096 1070 // base type to treat the aggregate as the referenced value 1097 1071 Cost addedCost = Cost::zero; … … 1100 1074 // find member of the given type 1101 1075 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1102 addAggMembers( 1076 addAggMembers( 1103 1077 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1104 1078 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1105 addAggMembers( 1079 addAggMembers( 1106 1080 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1107 1081 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1118 1092 std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name ); 1119 1093 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1120 if( declList.empty() ) return;1121 1122 reason.code = NoMatch;1123 1124 1094 for ( auto & data : declList ) { 1125 1095 Cost cost = Cost::zero; … … 1127 1097 1128 1098 CandidateRef newCand = std::make_shared<Candidate>( 1129 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1099 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1130 1100 cost ); 1131 1101 PRINT( … … 1137 1107 std::cerr << std::endl; 1138 1108 ) 1139 newCand->expr = ast::mutate_field( 1140 newCand->expr.get(), &ast::Expr::result, 1109 newCand->expr = ast::mutate_field( 1110 newCand->expr.get(), &ast::Expr::result, 1141 1111 renameTyVars( newCand->expr->result ) ); 1142 // add anonymous member interpretations whenever an aggregate value type is seen 1112 // add anonymous member interpretations whenever an aggregate value type is seen 1143 1113 // as a name expression 1144 1114 addAnonConversions( newCand ); … … 1150 1120 // not sufficient to just pass `variableExpr` here, type might have changed since 1151 1121 // creation 1152 addCandidate( 1122 addCandidate( 1153 1123 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1154 1124 } … … 1160 1130 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1161 1131 if ( sizeofExpr->type ) { 1162 addCandidate( 1163 new ast::SizeofExpr{ 1164 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1132 addCandidate( 1133 new ast::SizeofExpr{ 1134 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1165 1135 tenv ); 1166 1136 } else { … … 1171 1141 CandidateList winners = findMinCost( finder.candidates ); 1172 1142 if ( winners.size() != 1 ) { 1173 SemanticError( 1143 SemanticError( 1174 1144 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1175 1145 } … … 1184 1154 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1185 1155 if ( alignofExpr->type ) { 1186 addCandidate( 1187 new ast::AlignofExpr{ 1188 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1156 addCandidate( 1157 new ast::AlignofExpr{ 1158 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1189 1159 tenv ); 1190 1160 } else { … … 1195 1165 CandidateList winners = findMinCost( finder.candidates ); 1196 1166 if ( winners.size() != 1 ) { 1197 SemanticError( 1167 SemanticError( 1198 1168 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1199 1169 } … … 1202 1172 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1203 1173 choice->cost = Cost::zero; 1204 addCandidate( 1174 addCandidate( 1205 1175 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1206 1176 } … … 1215 1185 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1216 1186 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1217 addCandidate( 1187 addCandidate( 1218 1188 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1219 1189 } … … 1236 1206 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1237 1207 if ( finder2.candidates.empty() ) return; 1238 1239 reason.code = NoMatch;1240 1208 1241 1209 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1250 1218 1251 1219 addCandidate( 1252 new ast::LogicalExpr{ 1220 new ast::LogicalExpr{ 1253 1221 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1254 1222 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1272 1240 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1273 1241 if ( finder3.candidates.empty() ) return; 1274 1275 reason.code = NoMatch;1276 1242 1277 1243 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1290 1256 ast::AssertionSet have; 1291 1257 1292 // unify true and false results, then infer parameters to produce new 1258 // unify true and false results, then infer parameters to produce new 1293 1259 // candidates 1294 1260 ast::ptr< ast::Type > common; 1295 if ( 1296 unify( 1297 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1298 common ) 1261 if ( 1262 unify( 1263 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1264 common ) 1299 1265 ) { 1300 1266 // generate typed expression 1301 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1267 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1302 1268 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1303 1269 newExpr->result = common ? common : r2->expr->result; 1304 1270 // convert both options to result type 1305 1271 Cost cost = r1->cost + r2->cost + r3->cost; 1306 newExpr->arg2 = computeExpressionConversionCost( 1272 newExpr->arg2 = computeExpressionConversionCost( 1307 1273 newExpr->arg2, newExpr->result, symtab, env, cost ); 1308 1274 newExpr->arg3 = computeExpressionConversionCost( … … 1321 1287 ast::TypeEnvironment env{ tenv }; 1322 1288 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1323 1289 1324 1290 CandidateFinder finder2{ symtab, env }; 1325 1291 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1351 1317 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1352 1318 if ( finder2.candidates.empty() ) return; 1353 1354 reason.code = NoMatch;1355 1319 1356 1320 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1366 1330 1367 1331 ast::ptr< ast::Type > common; 1368 if ( 1369 unify( 1370 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1371 common ) 1332 if ( 1333 unify( 1334 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1335 common ) 1372 1336 ) { 1373 1337 // generate new expression 1374 ast::RangeExpr * newExpr = 1338 ast::RangeExpr * newExpr = 1375 1339 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1376 1340 newExpr->result = common ? common : r1->expr->result; 1377 1341 // add candidate 1378 1342 CandidateRef newCand = std::make_shared<Candidate>( 1379 newExpr, move( env ), move( open ), move( need ), 1343 newExpr, move( env ), move( open ), move( need ), 1380 1344 r1->cost + r2->cost ); 1381 1345 inferParameters( newCand, candidates ); … … 1386 1350 1387 1351 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1388 std::vector< CandidateFinder > subCandidates = 1352 std::vector< CandidateFinder > subCandidates = 1389 1353 selfFinder.findSubExprs( tupleExpr->exprs ); 1390 1354 std::vector< CandidateList > possibilities; … … 1406 1370 1407 1371 addCandidate( 1408 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1372 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1409 1373 move( env ), move( open ), move( need ), sumCost( subs ) ); 1410 1374 } … … 1448 1412 toType = SymTab::validateType( initExpr->location, toType, symtab ); 1449 1413 toType = adjustExprType( toType, tenv, symtab ); 1450 // The call to find must occur inside this loop, otherwise polymorphic return 1451 // types are not bound to the initialization type, since return type variables are 1452 // 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. 1453 1417 CandidateFinder finder{ symtab, tenv, toType }; 1454 1418 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1455 1419 for ( CandidateRef & cand : finder.candidates ) { 1456 if(reason.code == NotFound) reason.code = NoMatch;1457 1458 1420 ast::TypeEnvironment env{ cand->env }; 1459 1421 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; … … 1464 1426 ) 1465 1427 1466 // It is possible that a cast can throw away some values in a multiply-valued 1467 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1468 // 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 1469 1431 // if it has fewer results than there are types to cast to. 1470 1432 int discardedValues = cand->expr->result->size() - toType->size(); … … 1473 1435 // unification run for side-effects 1474 1436 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1475 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1476 symtab, env ); 1477 1437 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1438 1478 1439 if ( thisCost != Cost::infinity ) { 1479 1440 // count one safe conversion for each value that is thrown away 1480 1441 thisCost.incSafe( discardedValues ); 1481 CandidateRef newCand = std::make_shared<Candidate>( 1482 new ast::InitExpr{ 1483 initExpr->location, restructureCast( cand->expr, toType ), 1484 initAlt.designation }, 1485 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 ); 1486 1447 inferParameters( newCand, matches ); 1487 1448 } … … 1508 1469 }; 1509 1470 1510 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder"); 1511 /// 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 1512 1472 /// return type. Skips ambiguous candidates. 1513 1473 CandidateList pruneCandidates( CandidateList & candidates ) { … … 1526 1486 { 1527 1487 ast::ptr< ast::Type > newType = candidate->expr->result; 1528 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());1529 1488 candidate->env.apply( newType ); 1530 1489 mangleName = Mangle::mangle( newType ); … … 1535 1494 if ( candidate->cost < found->second.candidate->cost ) { 1536 1495 PRINT( 1537 std::cerr << "cost " << candidate->cost << " beats " 1496 std::cerr << "cost " << candidate->cost << " beats " 1538 1497 << found->second.candidate->cost << std::endl; 1539 1498 ) … … 1541 1500 found->second = PruneStruct{ candidate }; 1542 1501 } else if ( candidate->cost == found->second.candidate->cost ) { 1543 // if one of the candidates contains a deleted identifier, can pick the other, 1544 // since deleted expressions should not be ambiguous if there is another option 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 1545 1504 // that is at least as good 1546 1505 if ( findDeletedExpr( candidate->expr ) ) { … … 1556 1515 } else { 1557 1516 PRINT( 1558 std::cerr << "cost " << candidate->cost << " loses to " 1517 std::cerr << "cost " << candidate->cost << " loses to " 1559 1518 << found->second.candidate->cost << std::endl; 1560 1519 ) … … 1571 1530 1572 1531 CandidateRef cand = target.second.candidate; 1573 1532 1574 1533 ast::ptr< ast::Type > newResult = cand->expr->result; 1575 1534 cand->env.applyFree( newResult ); 1576 1535 cand->expr = ast::mutate_field( 1577 1536 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1578 1537 1579 1538 out.emplace_back( cand ); 1580 1539 } … … 1590 1549 1591 1550 if ( mode.failFast && candidates.empty() ) { 1592 switch(finder.core.reason.code) { 1593 case Finder::NotFound: 1594 { SemanticError( expr, "No alternatives for expression " ); break; } 1595 case Finder::NoMatch: 1596 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1597 case Finder::ArgsToFew: 1598 case Finder::ArgsToMany: 1599 case Finder::RetsToFew: 1600 case Finder::RetsToMany: 1601 case Finder::NoReason: 1602 default: 1603 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1604 } 1551 SemanticError( expr, "No reasonable alternatives for expression " ); 1605 1552 } 1606 1553 … … 1611 1558 std::vector< std::string > errors; 1612 1559 for ( CandidateRef & candidate : candidates ) { 1613 satisfyAssertions( candidate, localSyms, satisfied, errors );1560 satisfyAssertions( candidate, symtab, satisfied, errors ); 1614 1561 } 1615 1562 … … 1636 1583 1637 1584 CandidateList pruned = pruneCandidates( candidates ); 1638 1585 1639 1586 if ( mode.failFast && pruned.empty() ) { 1640 1587 std::ostringstream stream; … … 1655 1602 ) 1656 1603 PRINT( 1657 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1658 1605 << std::endl; 1659 1606 ) 1660 1607 } 1661 1608 1662 // 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 1663 1610 // adjusted 1664 1611 if ( mode.adjust ) { 1665 1612 for ( CandidateRef & r : candidates ) { 1666 r->expr = ast::mutate_field( 1667 r->expr.get(), &ast::Expr::result, 1668 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 ) ); 1669 1616 } 1670 1617 } … … 1678 1625 } 1679 1626 1680 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1681 const std::vector< ast::ptr< ast::Expr > > & xs 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1682 1629 ) { 1683 1630 std::vector< CandidateFinder > out; 1684 1631 1685 1632 for ( const auto & x : xs ) { 1686 out.emplace_back( localSyms, env );1633 out.emplace_back( symtab, env ); 1687 1634 out.back().find( x, ResolvMode::withAdjustment() ); 1688 1635 1689 1636 PRINT( 1690 1637 std::cerr << "findSubExprs" << std::endl;
Note:
See TracChangeset
for help on using the changeset viewer.