- File:
-
- 1 edited
-
src/ResolvExpr/CandidateFinder.cpp (modified) (85 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CandidateFinder.cpp
r18e683b rcf32116 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 14:55:00 2019 13 // Update Count : 2 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, const ast::SymbolTable & symtab,65 const ast:: TypeEnvironment & env63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 65 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 66 66 ) { 67 67 PRINT( … … 74 74 std::cerr << std::endl; 75 75 ) 76 Cost convCost = conversionCost( argType, paramType, symtab, env );76 Cost convCost = conversionCost( argType, paramType, argIsLvalue, 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( arg->result, paramType, symtab, env ); 112 Cost convCost = computeConversionCost( 113 arg->result, paramType, arg->get_lvalue(), symtab, env ); 113 114 outCost += convCost; 114 115 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 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 117 118 // infer parameters and this does not currently work for the reason stated below 118 119 Cost tmpCost = convCost; … … 123 124 return new ast::CastExpr{ arg, newType }; 124 125 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, 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, 127 128 // once this is fixed it should be possible to resolve the cast. 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 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 130 131 // commontype(zero_t, DT*) is DT*, rather than nothing 131 132 132 133 // CandidateFinder finder{ symtab, env }; 133 134 // finder.find( arg, ResolvMode::withAdjustment() ); 134 // assertf( finder.candidates.size() > 0, 135 // assertf( finder.candidates.size() > 0, 135 136 // "Somehow castable expression failed to find alternatives." ); 136 // assertf( finder.candidates.size() == 1, 137 // assertf( finder.candidates.size() == 1, 137 138 // "Somehow got multiple alternatives for known cast expression." ); 138 139 // return finder.candidates.front()->expr; … … 143 144 144 145 /// Computes conversion cost for a given candidate 145 Cost computeApplicationConversionCost( 146 CandidateRef cand, const ast::SymbolTable & symtab 146 Cost computeApplicationConversionCost( 147 CandidateRef cand, const ast::SymbolTable & symtab 147 148 ) { 148 149 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); … … 167 168 if ( function->isVarArgs ) { 168 169 convCost.incUnsafe(); 169 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 171 << convCost << std::endl; ; ) 171 172 // convert reference-typed expressions into value-typed expressions 172 cand->expr = ast::mutate_field_index( 173 appExpr, &ast::ApplicationExpr::args, i, 173 cand->expr = ast::mutate_field_index( 174 appExpr, &ast::ApplicationExpr::args, i, 174 175 referenceToRvalueConversion( args[i], convCost ) ); 175 176 continue; … … 180 181 // Default arguments should be free - don't include conversion cost. 181 182 // Unwrap them here because they are not relevant to the rest of the system 182 cand->expr = ast::mutate_field_index( 183 cand->expr = ast::mutate_field_index( 183 184 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 184 185 ++param; … … 188 189 // mark conversion cost and also specialization cost of param type 189 190 const ast::Type * paramType = (*param)->get_type(); 190 cand->expr = ast::mutate_field_index( 191 appExpr, &ast::ApplicationExpr::args, i, 192 computeExpressionConversionCost( 191 cand->expr = ast::mutate_field_index( 192 appExpr, &ast::ApplicationExpr::args, i, 193 computeExpressionConversionCost( 193 194 args[i], paramType, symtab, cand->env, convCost ) ); 194 195 convCost.decSpec( specCost( paramType ) ); … … 198 199 if ( param != params.end() ) return Cost::infinity; 199 200 200 // specialization cost of return types can't be accounted for directly, it disables 201 // specialization cost of return types can't be accounted for directly, it disables 201 202 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 202 203 // … … 215 216 } 216 217 217 void makeUnifiableVars( 218 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 219 ast::AssertionSet & need 218 void makeUnifiableVars( 219 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 220 ast::AssertionSet & need 220 221 ) { 221 222 for ( const ast::TypeDecl * tyvar : type->forall ) { … … 254 255 255 256 ArgPack() 256 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 258 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 258 259 ArgPack( 260 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 259 260 ArgPack( 261 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 261 262 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 262 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 264 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 264 265 265 266 ArgPack( 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, 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, 269 270 unsigned nextExpl = 0, unsigned explAlt = 0 ) 270 271 : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ), 271 272 have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 272 273 nextExpl( nextExpl ), explAlt( explAlt ) {} 273 274 274 275 ArgPack( 275 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 277 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 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 ), 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 ), 279 280 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 280 281 281 282 /// true if this pack is in the middle of an exploded argument 282 283 bool hasExpl() const { return nextExpl > 0; } … … 286 287 return args[ nextArg-1 ][ explAlt ]; 287 288 } 288 289 289 290 /// Ends a tuple expression, consolidating the appropriate args 290 291 void endTuple( const std::vector< ArgPack > & packs ) { … … 307 308 308 309 /// Instantiates an argument to match a parameter, returns false if no matching results left 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 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 313 314 ) { 314 315 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { … … 318 319 // xxx - dropping initializer changes behaviour from previous, but seems correct 319 320 // ^^^ need to handle the case where a tuple has a default argument 320 if ( ! instantiateArgument( 321 if ( ! instantiateArgument( 321 322 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 322 323 nTuples = 0; … … 329 330 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 330 331 // paramType is a ttype, consumes all remaining arguments 331 332 332 333 // completed tuples; will be spliced to end of results to finish 333 334 std::vector< ArgPack > finalResults{}; … … 342 343 for ( std::size_t i = genStart; i < genEnd; ++i ) { 343 344 unsigned nextArg = results[i].nextArg; 344 345 345 346 // use next element of exploded tuple if present 346 347 if ( results[i].hasExpl() ) { … … 352 353 results.emplace_back( 353 354 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 354 copy( results[i].need ), copy( results[i].have ), 355 copy( results[i].need ), copy( results[i].have ), 355 356 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 356 357 results[i].explAlt ); … … 370 371 // push empty tuple expression 371 372 newResult.parent = i; 372 std::vector< ast::ptr< ast::Expr > > emptyList; 373 newResult.expr = 374 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) }; 373 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} }; 375 374 argType = newResult.expr->result; 376 375 } else { … … 400 399 401 400 // check unification for ttype before adding to final 402 if ( 403 unify( 401 if ( 402 unify( 404 403 ttype, argType, newResult.env, newResult.need, newResult.have, 405 newResult.open, symtab ) 404 newResult.open, symtab ) 406 405 ) { 407 406 finalResults.emplace_back( move( newResult ) ); … … 424 423 if ( expl.exprs.empty() ) { 425 424 results.emplace_back( 426 results[i], move( env ), copy( results[i].need ), 425 results[i], move( env ), copy( results[i].need ), 427 426 copy( results[i].have ), move( open ), nextArg + 1, expl.cost ); 428 427 429 428 continue; 430 429 } … … 432 431 // add new result 433 432 results.emplace_back( 434 i, expl.exprs.front(), move( env ), copy( results[i].need ), 435 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 433 i, expl.exprs.front(), move( env ), copy( results[i].need ), 434 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 436 435 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 437 436 } … … 479 478 480 479 results.emplace_back( 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 480 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 482 481 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 483 482 } … … 495 494 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 496 495 results.emplace_back( 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 496 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 498 497 move( need ), move( have ), move( open ), nextArg, nTuples ); 499 498 } … … 517 516 if ( expl.exprs.empty() ) { 518 517 results.emplace_back( 519 results[i], move( env ), move( need ), move( have ), move( open ), 518 results[i], move( env ), move( need ), move( have ), move( open ), 520 519 nextArg + 1, expl.cost ); 521 520 522 521 continue; 523 522 } … … 539 538 // add new result 540 539 results.emplace_back( 541 i, expr, move( env ), move( need ), move( have ), move( open ), 540 i, expr, move( env ), move( need ), move( have ), move( open ), 542 541 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 543 542 } … … 548 547 genStart = genEnd; 549 548 550 return genEnd != results.size(); 549 return genEnd != results.size(); // were any new results added? 551 550 } 552 551 553 552 /// Generate a cast expression from `arg` to `toType` 554 const ast::Expr * restructureCast( 553 const ast::Expr * restructureCast( 555 554 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 556 555 ) { 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 556 if ( 557 arg->result->size() > 1 558 && ! toType->isVoid() 559 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 561 560 ) { 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 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 566 565 // UniqueExpr ensures that the side effects will still be produced) 567 566 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 568 // expressions which may contain side effects require a single unique instance of 567 // expressions which may contain side effects require a single unique instance of 569 568 // the expression 570 569 arg = new ast::UniqueExpr{ arg->location, arg }; … … 574 573 // cast each component 575 574 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 576 components.emplace_back( 575 components.emplace_back( 577 576 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 578 577 } … … 594 593 595 594 /// Actually visits expressions to find their candidate interpretations 596 struct Finder final : public ast::WithShortCircuiting { 595 class Finder final : public ast::WithShortCircuiting { 596 const ast::SymbolTable & symtab; 597 public: 597 598 CandidateFinder & selfFinder; 598 const ast::SymbolTable & symtab;599 599 CandidateList & candidates; 600 600 const ast::TypeEnvironment & tenv; … … 602 602 603 603 Finder( CandidateFinder & f ) 604 : s elfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),604 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 605 605 targetType( f.targetType ) {} 606 606 607 607 void previsit( const ast::Node * ) { visit_children = false; } 608 608 … … 639 639 640 640 /// Completes a function candidate with arguments located 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 644 644 ) { 645 ast::ApplicationExpr * appExpr = 645 ast::ApplicationExpr * appExpr = 646 646 new ast::ApplicationExpr{ func->expr->location, func->expr }; 647 647 // sum cost and accumulate arguments … … 657 657 appExpr->args = move( vargs ); 658 658 // build and validate new candidate 659 auto newCand = 659 auto newCand = 660 660 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 661 661 PRINT( … … 669 669 /// Builds a list of candidates for a function, storing them in out 670 670 void makeFunctionCandidates( 671 const CandidateRef & func, const ast::FunctionType * funcType, 671 const CandidateRef & func, const ast::FunctionType * funcType, 672 672 const ExplodedArgs_new & args, CandidateList & out 673 673 ) { … … 676 676 ast::TypeEnvironment funcEnv{ func->env }; 677 677 makeUnifiableVars( funcType, funcOpen, funcNeed ); 678 // add all type variables as open variables now so that those not used in the parameter679 // list are still considered open678 // add all type variables as open variables now so that those not used in the 679 // parameter list are still considered open 680 680 funcEnv.add( funcType->forall ); 681 681 … … 683 683 // attempt to narrow based on expected target type 684 684 const ast::Type * returnType = funcType->returns.front()->get_type(); 685 if ( ! unify( 686 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 685 if ( ! unify( 686 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 687 687 ) { 688 688 // unification failed, do not pursue this candidate … … 698 698 for ( const ast::DeclWithType * param : funcType->params ) { 699 699 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param ); 700 // 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 701 701 // matches 702 if ( ! instantiateArgument( 702 if ( ! instantiateArgument( 703 703 obj->type, obj->init, args, results, genStart, symtab ) ) return; 704 704 } … … 750 750 if ( expl.exprs.empty() ) { 751 751 results.emplace_back( 752 results[i], move( env ), copy( results[i].need ), 753 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, 754 754 expl.cost ); 755 755 … … 760 760 results.emplace_back( 761 761 i, expl.exprs.front(), move( env ), copy( results[i].need ), 762 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 762 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 763 763 expl.exprs.size() == 1 ? 0 : 1, j ); 764 764 } … … 780 780 /// Adds implicit struct-conversions to the alternative list 781 781 void addAnonConversions( const CandidateRef & cand ) { 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 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 784 784 // base type to treat the aggregate as the referenced value 785 785 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 786 786 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 787 787 cand->env.apply( aggrType ); 788 788 789 789 if ( aggrType.as< ast::ReferenceType >() ) { 790 790 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; … … 799 799 800 800 /// Adds aggregate member interpretations 801 void addAggMembers( 802 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 803 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 804 804 ) { 805 805 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 806 806 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 807 CandidateRef newCand = std::make_shared<Candidate>( 807 CandidateRef newCand = std::make_shared<Candidate>( 808 808 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 809 // add anonymous member interpretations whenever an aggregate value type is seen 809 // add anonymous member interpretations whenever an aggregate value type is seen 810 810 // as a member expression 811 811 addAnonConversions( newCand ); … … 815 815 816 816 /// Adds tuple member interpretations 817 void addTupleMembers( 818 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 819 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 820 820 ) { 821 821 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 822 // 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 823 823 // length of the tuple to have meaning 824 824 long long val = constantExpr->intValue(); 825 825 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 826 826 addCandidate( 827 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 827 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 828 828 addedCost ); 829 829 } … … 837 837 if ( funcFinder.candidates.empty() ) return; 838 838 839 std::vector< CandidateFinder > argCandidates = 839 std::vector< CandidateFinder > argCandidates = 840 840 selfFinder.findSubExprs( untypedExpr->args ); 841 841 842 842 // take care of possible tuple assignments 843 843 // if not tuple assignment, handled as normal function call … … 877 877 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 878 878 CandidateRef newFunc{ new Candidate{ *func } }; 879 newFunc->expr = 879 newFunc->expr = 880 880 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 881 881 makeFunctionCandidates( newFunc, function, argExpansions, found ); 882 882 } 883 } else if ( 884 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 883 } else if ( 884 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 885 885 ) { 886 886 if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) { 887 887 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 888 888 CandidateRef newFunc{ new Candidate{ *func } }; 889 newFunc->expr = 889 newFunc->expr = 890 890 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 891 891 makeFunctionCandidates( newFunc, function, argExpansions, found ); … … 901 901 std::vector< ExplodedArg > funcE; 902 902 funcE.reserve( funcFinder.candidates.size() ); 903 for ( const CandidateRef & func : funcFinder ) { 903 for ( const CandidateRef & func : funcFinder ) { 904 904 funcE.emplace_back( *func, symtab ); 905 905 } … … 913 913 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 914 914 CandidateRef newOp{ new Candidate{ *op} }; 915 newOp->expr = 915 newOp->expr = 916 916 referenceToRvalueConversion( newOp->expr, newOp->cost ); 917 917 makeFunctionCandidates( newOp, function, argExpansions, found ); … … 922 922 } 923 923 924 // 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 925 925 // candidates 926 926 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } … … 934 934 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 935 935 auto function = pointer->base.strict_as< ast::FunctionType >(); 936 936 937 937 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 938 938 std::cerr << "parameters are:" << std::endl; … … 957 957 promoteCvtCost( winners ); 958 958 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 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 961 961 // `findMinCost`, since anon conversions are never the cheapest 962 962 for ( const CandidateRef & c : winners ) { … … 966 966 967 967 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 968 // 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 969 969 // will sometimes succeed when it wouldn't with a target type binding. 970 970 // For example: … … 983 983 /// true if expression is an lvalue 984 984 static bool isLvalue( const ast::Expr * x ) { 985 return x->result && ( x-> result->is_lvalue() || x->result.as< ast::ReferenceType >() );985 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 986 986 } 987 987 … … 1016 1016 cand->env.extractOpenVars( open ); 1017 1017 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 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 1021 1021 // has fewer results than there are types to cast to. 1022 1022 int discardedValues = cand->expr->result->size() - toType->size(); … … 1025 1025 // unification run for side-effects 1026 1026 unify( toType, cand->expr->result, cand->env, need, have, open, symtab ); 1027 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env ); 1027 Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1028 symtab, cand->env ); 1028 1029 PRINT( 1029 1030 std::cerr << "working on cast with result: " << toType << std::endl; … … 1037 1038 // count one safe conversion for each value that is thrown away 1038 1039 thisCost.incSafe( discardedValues ); 1039 CandidateRef newCand = std::make_shared<Candidate>( 1040 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1041 copy( cand->env ), move( open ), move( need ), cand->cost, 1040 CandidateRef newCand = std::make_shared<Candidate>( 1041 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1042 copy( cand->env ), move( open ), move( need ), cand->cost, 1042 1043 cand->cost + thisCost ); 1043 1044 inferParameters( newCand, matches ); … … 1057 1058 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1058 1059 for ( CandidateRef & r : finder.candidates ) { 1059 addCandidate( 1060 *r, 1060 addCandidate( 1061 *r, 1061 1062 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1062 1063 } … … 1067 1068 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1068 1069 for ( CandidateRef & agg : aggFinder.candidates ) { 1069 // it's okay for the aggregate expression to have reference type -- cast it to the 1070 // it's okay for the aggregate expression to have reference type -- cast it to the 1070 1071 // base type to treat the aggregate as the referenced value 1071 1072 Cost addedCost = Cost::zero; … … 1074 1075 // find member of the given type 1075 1076 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1076 addAggMembers( 1077 addAggMembers( 1077 1078 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1078 1079 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1079 addAggMembers( 1080 addAggMembers( 1080 1081 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1081 1082 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1097 1098 1098 1099 CandidateRef newCand = std::make_shared<Candidate>( 1099 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1100 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1100 1101 cost ); 1101 1102 PRINT( … … 1107 1108 std::cerr << std::endl; 1108 1109 ) 1109 newCand->expr = ast::mutate_field( 1110 newCand->expr.get(), &ast::Expr::result, 1110 newCand->expr = ast::mutate_field( 1111 newCand->expr.get(), &ast::Expr::result, 1111 1112 renameTyVars( newCand->expr->result ) ); 1112 // add anonymous member interpretations whenever an aggregate value type is seen 1113 // add anonymous member interpretations whenever an aggregate value type is seen 1113 1114 // as a name expression 1114 1115 addAnonConversions( newCand ); … … 1120 1121 // not sufficient to just pass `variableExpr` here, type might have changed since 1121 1122 // creation 1122 addCandidate( 1123 addCandidate( 1123 1124 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1124 1125 } … … 1130 1131 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1131 1132 if ( sizeofExpr->type ) { 1132 addCandidate( 1133 new ast::SizeofExpr{ 1134 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1133 addCandidate( 1134 new ast::SizeofExpr{ 1135 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1135 1136 tenv ); 1136 1137 } else { … … 1141 1142 CandidateList winners = findMinCost( finder.candidates ); 1142 1143 if ( winners.size() != 1 ) { 1143 SemanticError( 1144 SemanticError( 1144 1145 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1145 1146 } … … 1154 1155 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1155 1156 if ( alignofExpr->type ) { 1156 addCandidate( 1157 new ast::AlignofExpr{ 1158 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1157 addCandidate( 1158 new ast::AlignofExpr{ 1159 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1159 1160 tenv ); 1160 1161 } else { … … 1165 1166 CandidateList winners = findMinCost( finder.candidates ); 1166 1167 if ( winners.size() != 1 ) { 1167 SemanticError( 1168 SemanticError( 1168 1169 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1169 1170 } … … 1172 1173 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1173 1174 choice->cost = Cost::zero; 1174 addCandidate( 1175 addCandidate( 1175 1176 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1176 1177 } … … 1185 1186 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1186 1187 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1187 addCandidate( 1188 addCandidate( 1188 1189 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1189 1190 } … … 1218 1219 1219 1220 addCandidate( 1220 new ast::LogicalExpr{ 1221 new ast::LogicalExpr{ 1221 1222 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1222 1223 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1256 1257 ast::AssertionSet have; 1257 1258 1258 // unify true and false results, then infer parameters to produce new 1259 // unify true and false results, then infer parameters to produce new 1259 1260 // candidates 1260 1261 ast::ptr< ast::Type > common; 1261 if ( 1262 unify( 1263 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1264 common ) 1262 if ( 1263 unify( 1264 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1265 common ) 1265 1266 ) { 1266 1267 // generate typed expression 1267 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1268 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1268 1269 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1269 1270 newExpr->result = common ? common : r2->expr->result; 1270 1271 // convert both options to result type 1271 1272 Cost cost = r1->cost + r2->cost + r3->cost; 1272 newExpr->arg2 = computeExpressionConversionCost( 1273 newExpr->arg2 = computeExpressionConversionCost( 1273 1274 newExpr->arg2, newExpr->result, symtab, env, cost ); 1274 1275 newExpr->arg3 = computeExpressionConversionCost( … … 1287 1288 ast::TypeEnvironment env{ tenv }; 1288 1289 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1289 1290 1290 1291 CandidateFinder finder2{ symtab, env }; 1291 1292 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1330 1331 1331 1332 ast::ptr< ast::Type > common; 1332 if ( 1333 unify( 1334 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1335 common ) 1333 if ( 1334 unify( 1335 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1336 common ) 1336 1337 ) { 1337 1338 // generate new expression 1338 ast::RangeExpr * newExpr = 1339 ast::RangeExpr * newExpr = 1339 1340 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1340 1341 newExpr->result = common ? common : r1->expr->result; 1341 1342 // add candidate 1342 1343 CandidateRef newCand = std::make_shared<Candidate>( 1343 newExpr, move( env ), move( open ), move( need ), 1344 newExpr, move( env ), move( open ), move( need ), 1344 1345 r1->cost + r2->cost ); 1345 1346 inferParameters( newCand, candidates ); … … 1350 1351 1351 1352 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1352 std::vector< CandidateFinder > subCandidates = 1353 std::vector< CandidateFinder > subCandidates = 1353 1354 selfFinder.findSubExprs( tupleExpr->exprs ); 1354 1355 std::vector< CandidateList > possibilities; … … 1370 1371 1371 1372 addCandidate( 1372 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1373 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1373 1374 move( env ), move( open ), move( need ), sumCost( subs ) ); 1374 1375 } … … 1412 1413 toType = SymTab::validateType( initExpr->location, toType, symtab ); 1413 1414 toType = adjustExprType( toType, tenv, symtab ); 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. 1415 // The call to find must occur inside this loop, otherwise polymorphic return 1416 // types are not bound to the initialization type, since return type variables are 1417 // only open for the duration of resolving the UntypedExpr. 1417 1418 CandidateFinder finder{ symtab, tenv, toType }; 1418 1419 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); … … 1426 1427 ) 1427 1428 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 1429 // It is possible that a cast can throw away some values in a multiply-valued 1430 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1431 // the subexpression results that are cast directly. The candidate is invalid 1431 1432 // if it has fewer results than there are types to cast to. 1432 1433 int discardedValues = cand->expr->result->size() - toType->size(); … … 1435 1436 // unification run for side-effects 1436 1437 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1437 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1438 1438 Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1439 symtab, env ); 1440 1439 1441 if ( thisCost != Cost::infinity ) { 1440 1442 // count one safe conversion for each value that is thrown away 1441 1443 thisCost.incSafe( discardedValues ); 1442 CandidateRef newCand = std::make_shared<Candidate>( 1443 new ast::InitExpr{ 1444 initExpr->location, restructureCast( cand->expr, toType ), 1445 initAlt.designation }, 1444 CandidateRef newCand = std::make_shared<Candidate>( 1445 new ast::InitExpr{ 1446 initExpr->location, restructureCast( cand->expr, toType ), 1447 initAlt.designation }, 1446 1448 copy( cand->env ), move( open ), move( need ), cand->cost, thisCost ); 1447 1449 inferParameters( newCand, matches ); … … 1469 1471 }; 1470 1472 1471 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1473 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1472 1474 /// return type. Skips ambiguous candidates. 1473 1475 CandidateList pruneCandidates( CandidateList & candidates ) { … … 1486 1488 { 1487 1489 ast::ptr< ast::Type > newType = candidate->expr->result; 1490 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1488 1491 candidate->env.apply( newType ); 1489 1492 mangleName = Mangle::mangle( newType ); … … 1494 1497 if ( candidate->cost < found->second.candidate->cost ) { 1495 1498 PRINT( 1496 std::cerr << "cost " << candidate->cost << " beats " 1499 std::cerr << "cost " << candidate->cost << " beats " 1497 1500 << found->second.candidate->cost << std::endl; 1498 1501 ) … … 1500 1503 found->second = PruneStruct{ candidate }; 1501 1504 } else if ( candidate->cost == found->second.candidate->cost ) { 1502 // if one of the candidates contains a deleted identifier, can pick the other, 1503 // since deleted expressions should not be ambiguous if there is another option 1505 // if one of the candidates contains a deleted identifier, can pick the other, 1506 // since deleted expressions should not be ambiguous if there is another option 1504 1507 // that is at least as good 1505 1508 if ( findDeletedExpr( candidate->expr ) ) { … … 1515 1518 } else { 1516 1519 PRINT( 1517 std::cerr << "cost " << candidate->cost << " loses to " 1520 std::cerr << "cost " << candidate->cost << " loses to " 1518 1521 << found->second.candidate->cost << std::endl; 1519 1522 ) … … 1530 1533 1531 1534 CandidateRef cand = target.second.candidate; 1532 1535 1533 1536 ast::ptr< ast::Type > newResult = cand->expr->result; 1534 1537 cand->env.applyFree( newResult ); 1535 1538 cand->expr = ast::mutate_field( 1536 1539 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1537 1540 1538 1541 out.emplace_back( cand ); 1539 1542 } … … 1558 1561 std::vector< std::string > errors; 1559 1562 for ( CandidateRef & candidate : candidates ) { 1560 satisfyAssertions( candidate, symtab, satisfied, errors );1563 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1561 1564 } 1562 1565 … … 1583 1586 1584 1587 CandidateList pruned = pruneCandidates( candidates ); 1585 1588 1586 1589 if ( mode.failFast && pruned.empty() ) { 1587 1590 std::ostringstream stream; … … 1602 1605 ) 1603 1606 PRINT( 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1607 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1605 1608 << std::endl; 1606 1609 ) 1607 1610 } 1608 1611 1609 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1612 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1610 1613 // adjusted 1611 1614 if ( mode.adjust ) { 1612 1615 for ( CandidateRef & r : candidates ) { 1613 r->expr = ast::mutate_field( 1614 r->expr.get(), &ast::Expr::result, 1615 adjustExprType( r->expr->result, r->env, symtab) );1616 r->expr = ast::mutate_field( 1617 r->expr.get(), &ast::Expr::result, 1618 adjustExprType( r->expr->result, r->env, localSyms ) ); 1616 1619 } 1617 1620 } … … 1625 1628 } 1626 1629 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1630 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1631 const std::vector< ast::ptr< ast::Expr > > & xs 1629 1632 ) { 1630 1633 std::vector< CandidateFinder > out; 1631 1634 1632 1635 for ( const auto & x : xs ) { 1633 out.emplace_back( symtab, env );1636 out.emplace_back( localSyms, env ); 1634 1637 out.back().find( x, ResolvMode::withAdjustment() ); 1635 1638 1636 1639 PRINT( 1637 1640 std::cerr << "findSubExprs" << std::endl;
Note:
See TracChangeset
for help on using the changeset viewer.