- File:
-
- 1 edited
-
src/ResolvExpr/CandidateFinder.cpp (modified) (85 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CandidateFinder.cpp
rcf32116 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 CandidateFinder & selfFinder;599 599 CandidateList & candidates; 600 600 const ast::TypeEnvironment & tenv; … … 602 602 603 603 Finder( CandidateFinder & f ) 604 : s ymtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),604 : selfFinder( f ), symtab( f.symtab ), 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 679 // 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 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-> get_lvalue() || x->result.as< ast::ReferenceType >() );985 return x->result && ( x->result->is_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, cand->expr->get_lvalue(), 1028 symtab, cand->env ); 1027 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env ); 1029 1028 PRINT( 1030 1029 std::cerr << "working on cast with result: " << toType << std::endl; … … 1038 1037 // count one safe conversion for each value that is thrown away 1039 1038 thisCost.incSafe( discardedValues ); 1040 CandidateRef newCand = std::make_shared<Candidate>( 1041 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1042 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, 1043 1042 cand->cost + thisCost ); 1044 1043 inferParameters( newCand, matches ); … … 1058 1057 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1059 1058 for ( CandidateRef & r : finder.candidates ) { 1060 addCandidate( 1061 *r, 1059 addCandidate( 1060 *r, 1062 1061 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1063 1062 } … … 1068 1067 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1069 1068 for ( CandidateRef & agg : aggFinder.candidates ) { 1070 // 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 1071 1070 // base type to treat the aggregate as the referenced value 1072 1071 Cost addedCost = Cost::zero; … … 1075 1074 // find member of the given type 1076 1075 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1077 addAggMembers( 1076 addAggMembers( 1078 1077 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1079 1078 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1080 addAggMembers( 1079 addAggMembers( 1081 1080 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1082 1081 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1098 1097 1099 1098 CandidateRef newCand = std::make_shared<Candidate>( 1100 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1099 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1101 1100 cost ); 1102 1101 PRINT( … … 1108 1107 std::cerr << std::endl; 1109 1108 ) 1110 newCand->expr = ast::mutate_field( 1111 newCand->expr.get(), &ast::Expr::result, 1109 newCand->expr = ast::mutate_field( 1110 newCand->expr.get(), &ast::Expr::result, 1112 1111 renameTyVars( newCand->expr->result ) ); 1113 // add anonymous member interpretations whenever an aggregate value type is seen 1112 // add anonymous member interpretations whenever an aggregate value type is seen 1114 1113 // as a name expression 1115 1114 addAnonConversions( newCand ); … … 1121 1120 // not sufficient to just pass `variableExpr` here, type might have changed since 1122 1121 // creation 1123 addCandidate( 1122 addCandidate( 1124 1123 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1125 1124 } … … 1131 1130 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1132 1131 if ( sizeofExpr->type ) { 1133 addCandidate( 1134 new ast::SizeofExpr{ 1135 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1132 addCandidate( 1133 new ast::SizeofExpr{ 1134 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1136 1135 tenv ); 1137 1136 } else { … … 1142 1141 CandidateList winners = findMinCost( finder.candidates ); 1143 1142 if ( winners.size() != 1 ) { 1144 SemanticError( 1143 SemanticError( 1145 1144 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1146 1145 } … … 1155 1154 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1156 1155 if ( alignofExpr->type ) { 1157 addCandidate( 1158 new ast::AlignofExpr{ 1159 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1156 addCandidate( 1157 new ast::AlignofExpr{ 1158 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1160 1159 tenv ); 1161 1160 } else { … … 1166 1165 CandidateList winners = findMinCost( finder.candidates ); 1167 1166 if ( winners.size() != 1 ) { 1168 SemanticError( 1167 SemanticError( 1169 1168 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1170 1169 } … … 1173 1172 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1174 1173 choice->cost = Cost::zero; 1175 addCandidate( 1174 addCandidate( 1176 1175 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1177 1176 } … … 1186 1185 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1187 1186 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1188 addCandidate( 1187 addCandidate( 1189 1188 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1190 1189 } … … 1219 1218 1220 1219 addCandidate( 1221 new ast::LogicalExpr{ 1220 new ast::LogicalExpr{ 1222 1221 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1223 1222 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1257 1256 ast::AssertionSet have; 1258 1257 1259 // unify true and false results, then infer parameters to produce new 1258 // unify true and false results, then infer parameters to produce new 1260 1259 // candidates 1261 1260 ast::ptr< ast::Type > common; 1262 if ( 1263 unify( 1264 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1265 common ) 1261 if ( 1262 unify( 1263 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1264 common ) 1266 1265 ) { 1267 1266 // generate typed expression 1268 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1267 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1269 1268 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1270 1269 newExpr->result = common ? common : r2->expr->result; 1271 1270 // convert both options to result type 1272 1271 Cost cost = r1->cost + r2->cost + r3->cost; 1273 newExpr->arg2 = computeExpressionConversionCost( 1272 newExpr->arg2 = computeExpressionConversionCost( 1274 1273 newExpr->arg2, newExpr->result, symtab, env, cost ); 1275 1274 newExpr->arg3 = computeExpressionConversionCost( … … 1288 1287 ast::TypeEnvironment env{ tenv }; 1289 1288 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1290 1289 1291 1290 CandidateFinder finder2{ symtab, env }; 1292 1291 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1331 1330 1332 1331 ast::ptr< ast::Type > common; 1333 if ( 1334 unify( 1335 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1336 common ) 1332 if ( 1333 unify( 1334 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1335 common ) 1337 1336 ) { 1338 1337 // generate new expression 1339 ast::RangeExpr * newExpr = 1338 ast::RangeExpr * newExpr = 1340 1339 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1341 1340 newExpr->result = common ? common : r1->expr->result; 1342 1341 // add candidate 1343 1342 CandidateRef newCand = std::make_shared<Candidate>( 1344 newExpr, move( env ), move( open ), move( need ), 1343 newExpr, move( env ), move( open ), move( need ), 1345 1344 r1->cost + r2->cost ); 1346 1345 inferParameters( newCand, candidates ); … … 1351 1350 1352 1351 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1353 std::vector< CandidateFinder > subCandidates = 1352 std::vector< CandidateFinder > subCandidates = 1354 1353 selfFinder.findSubExprs( tupleExpr->exprs ); 1355 1354 std::vector< CandidateList > possibilities; … … 1371 1370 1372 1371 addCandidate( 1373 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1372 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1374 1373 move( env ), move( open ), move( need ), sumCost( subs ) ); 1375 1374 } … … 1413 1412 toType = SymTab::validateType( initExpr->location, toType, symtab ); 1414 1413 toType = adjustExprType( toType, tenv, symtab ); 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. 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. 1418 1417 CandidateFinder finder{ symtab, tenv, toType }; 1419 1418 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); … … 1427 1426 ) 1428 1427 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 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 1432 1431 // if it has fewer results than there are types to cast to. 1433 1432 int discardedValues = cand->expr->result->size() - toType->size(); … … 1436 1435 // unification run for side-effects 1437 1436 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1438 Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1439 symtab, env ); 1440 1437 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1438 1441 1439 if ( thisCost != Cost::infinity ) { 1442 1440 // count one safe conversion for each value that is thrown away 1443 1441 thisCost.incSafe( discardedValues ); 1444 CandidateRef newCand = std::make_shared<Candidate>( 1445 new ast::InitExpr{ 1446 initExpr->location, restructureCast( cand->expr, toType ), 1447 initAlt.designation }, 1442 CandidateRef newCand = std::make_shared<Candidate>( 1443 new ast::InitExpr{ 1444 initExpr->location, restructureCast( cand->expr, toType ), 1445 initAlt.designation }, 1448 1446 copy( cand->env ), move( open ), move( need ), cand->cost, thisCost ); 1449 1447 inferParameters( newCand, matches ); … … 1471 1469 }; 1472 1470 1473 /// 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 1474 1472 /// return type. Skips ambiguous candidates. 1475 1473 CandidateList pruneCandidates( CandidateList & candidates ) { … … 1488 1486 { 1489 1487 ast::ptr< ast::Type > newType = candidate->expr->result; 1490 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());1491 1488 candidate->env.apply( newType ); 1492 1489 mangleName = Mangle::mangle( newType ); … … 1497 1494 if ( candidate->cost < found->second.candidate->cost ) { 1498 1495 PRINT( 1499 std::cerr << "cost " << candidate->cost << " beats " 1496 std::cerr << "cost " << candidate->cost << " beats " 1500 1497 << found->second.candidate->cost << std::endl; 1501 1498 ) … … 1503 1500 found->second = PruneStruct{ candidate }; 1504 1501 } else if ( candidate->cost == found->second.candidate->cost ) { 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 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 1507 1504 // that is at least as good 1508 1505 if ( findDeletedExpr( candidate->expr ) ) { … … 1518 1515 } else { 1519 1516 PRINT( 1520 std::cerr << "cost " << candidate->cost << " loses to " 1517 std::cerr << "cost " << candidate->cost << " loses to " 1521 1518 << found->second.candidate->cost << std::endl; 1522 1519 ) … … 1533 1530 1534 1531 CandidateRef cand = target.second.candidate; 1535 1532 1536 1533 ast::ptr< ast::Type > newResult = cand->expr->result; 1537 1534 cand->env.applyFree( newResult ); 1538 1535 cand->expr = ast::mutate_field( 1539 1536 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1540 1537 1541 1538 out.emplace_back( cand ); 1542 1539 } … … 1561 1558 std::vector< std::string > errors; 1562 1559 for ( CandidateRef & candidate : candidates ) { 1563 satisfyAssertions( candidate, localSyms, satisfied, errors );1560 satisfyAssertions( candidate, symtab, satisfied, errors ); 1564 1561 } 1565 1562 … … 1586 1583 1587 1584 CandidateList pruned = pruneCandidates( candidates ); 1588 1585 1589 1586 if ( mode.failFast && pruned.empty() ) { 1590 1587 std::ostringstream stream; … … 1605 1602 ) 1606 1603 PRINT( 1607 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1608 1605 << std::endl; 1609 1606 ) 1610 1607 } 1611 1608 1612 // 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 1613 1610 // adjusted 1614 1611 if ( mode.adjust ) { 1615 1612 for ( CandidateRef & r : candidates ) { 1616 r->expr = ast::mutate_field( 1617 r->expr.get(), &ast::Expr::result, 1618 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 ) ); 1619 1616 } 1620 1617 } … … 1628 1625 } 1629 1626 1630 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1631 const std::vector< ast::ptr< ast::Expr > > & xs 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1632 1629 ) { 1633 1630 std::vector< CandidateFinder > out; 1634 1631 1635 1632 for ( const auto & x : xs ) { 1636 out.emplace_back( localSyms, env );1633 out.emplace_back( symtab, env ); 1637 1634 out.back().find( x, ResolvMode::withAdjustment() ); 1638 1635 1639 1636 PRINT( 1640 1637 std::cerr << "findSubExprs" << std::endl;
Note:
See TracChangeset
for help on using the changeset viewer.