- File:
-
- 1 edited
-
src/ResolvExpr/CandidateFinder.cpp (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CandidateFinder.cpp
r46da46b r251ce80 23 23 #include <vector> 24 24 25 #include "AdjustExprType.hpp" 25 26 #include "Candidate.hpp" 27 #include "CastCost.hpp" // for castCost 26 28 #include "CompilationState.h" 29 #include "ConversionCost.h" // for conversionCast 27 30 #include "Cost.h" 28 31 #include "ExplodedArg.hpp" 32 #include "PolyCost.hpp" 29 33 #include "RenameVars.h" // for renameTyVars 30 34 #include "Resolver.h" 31 35 #include "ResolveTypeof.h" 32 #include "WidenMode.h"33 36 #include "SatisfyAssertions.hpp" 34 #include "typeops.h" // for adjustExprType, conversionCost, polyCost, specCost 37 #include "SpecCost.hpp" 38 #include "typeops.h" // for combos 35 39 #include "Unify.h" 36 40 #include "AST/Expr.hpp" … … 51 55 namespace ResolvExpr { 52 56 57 /// Unique identifier for matching expression resolutions to their requesting expression 58 UniqueId globalResnSlot = 0; 59 60 namespace { 61 /// First index is which argument, second is which alternative, third is which exploded element 62 using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >; 63 64 /// Returns a list of alternatives with the minimum cost in the given list 65 CandidateList findMinCost( const CandidateList & candidates ) { 66 CandidateList out; 67 Cost minCost = Cost::infinity; 68 for ( const CandidateRef & r : candidates ) { 69 if ( r->cost < minCost ) { 70 minCost = r->cost; 71 out.clear(); 72 out.emplace_back( r ); 73 } else if ( r->cost == minCost ) { 74 out.emplace_back( r ); 75 } 76 } 77 return out; 78 } 79 80 /// Computes conversion cost for a given expression to a given type 81 const ast::Expr * computeExpressionConversionCost( 82 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 83 ) { 84 Cost convCost = computeConversionCost( 85 arg->result, paramType, arg->get_lvalue(), symtab, env ); 86 outCost += convCost; 87 88 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 89 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 90 // infer parameters and this does not currently work for the reason stated below 91 Cost tmpCost = convCost; 92 tmpCost.incPoly( -tmpCost.get_polyCost() ); 93 if ( tmpCost != Cost::zero ) { 94 ast::ptr< ast::Type > newType = paramType; 95 env.apply( newType ); 96 return new ast::CastExpr{ arg, newType }; 97 98 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 99 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 100 // once this is fixed it should be possible to resolve the cast. 101 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 102 // but it shouldn't be because this makes the conversion from DT* to DT* since 103 // commontype(zero_t, DT*) is DT*, rather than nothing 104 105 // CandidateFinder finder{ symtab, env }; 106 // finder.find( arg, ResolvMode::withAdjustment() ); 107 // assertf( finder.candidates.size() > 0, 108 // "Somehow castable expression failed to find alternatives." ); 109 // assertf( finder.candidates.size() == 1, 110 // "Somehow got multiple alternatives for known cast expression." ); 111 // return finder.candidates.front()->expr; 112 } 113 114 return arg; 115 } 116 117 /// Computes conversion cost for a given candidate 118 Cost computeApplicationConversionCost( 119 CandidateRef cand, const ast::SymbolTable & symtab 120 ) { 121 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); 122 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 123 auto function = pointer->base.strict_as< ast::FunctionType >(); 124 125 Cost convCost = Cost::zero; 126 const auto & params = function->params; 127 auto param = params.begin(); 128 auto & args = appExpr->args; 129 130 for ( unsigned i = 0; i < args.size(); ++i ) { 131 const ast::Type * argType = args[i]->result; 132 PRINT( 133 std::cerr << "arg expression:" << std::endl; 134 ast::print( std::cerr, args[i], 2 ); 135 std::cerr << "--- results are" << std::endl; 136 ast::print( std::cerr, argType, 2 ); 137 ) 138 139 if ( param == params.end() ) { 140 if ( function->isVarArgs ) { 141 convCost.incUnsafe(); 142 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 143 << convCost << std::endl; ; ) 144 // convert reference-typed expressions into value-typed expressions 145 cand->expr = ast::mutate_field_index( 146 appExpr, &ast::ApplicationExpr::args, i, 147 referenceToRvalueConversion( args[i], convCost ) ); 148 continue; 149 } else return Cost::infinity; 150 } 151 152 if ( auto def = args[i].as< ast::DefaultArgExpr >() ) { 153 // Default arguments should be free - don't include conversion cost. 154 // Unwrap them here because they are not relevant to the rest of the system 155 cand->expr = ast::mutate_field_index( 156 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 157 ++param; 158 continue; 159 } 160 161 // mark conversion cost and also specialization cost of param type 162 // const ast::Type * paramType = (*param)->get_type(); 163 cand->expr = ast::mutate_field_index( 164 appExpr, &ast::ApplicationExpr::args, i, 165 computeExpressionConversionCost( 166 args[i], *param, symtab, cand->env, convCost ) ); 167 convCost.decSpec( specCost( *param ) ); 168 ++param; // can't be in for-loop update because of the continue 169 } 170 171 if ( param != params.end() ) return Cost::infinity; 172 173 // specialization cost of return types can't be accounted for directly, it disables 174 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 175 // 176 // forall(otype OS) { 177 // void ?|?(OS&, int); // with newline 178 // OS& ?|?(OS&, int); // no newline, always chosen due to more specialization 179 // } 180 181 // mark type variable and specialization cost of forall clause 182 convCost.incVar( function->forall.size() ); 183 convCost.decSpec( function->assertions.size() ); 184 185 return convCost; 186 } 187 188 void makeUnifiableVars( 189 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars, 190 ast::AssertionSet & need 191 ) { 192 for ( auto & tyvar : type->forall ) { 193 unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base }; 194 } 195 for ( auto & assn : type->assertions ) { 196 need[ assn ].isUsed = true; 197 } 198 } 199 200 /// Gets a default value from an initializer, nullptr if not present 201 const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) { 202 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) { 203 if ( auto ce = si->value.as< ast::CastExpr >() ) { 204 return ce->arg.as< ast::ConstantExpr >(); 205 } else { 206 return si->value.as< ast::ConstantExpr >(); 207 } 208 } 209 return nullptr; 210 } 211 212 /// State to iteratively build a match of parameter expressions to arguments 213 struct ArgPack { 214 std::size_t parent; ///< Index of parent pack 215 ast::ptr< ast::Expr > expr; ///< The argument stored here 216 Cost cost; ///< The cost of this argument 217 ast::TypeEnvironment env; ///< Environment for this pack 218 ast::AssertionSet need; ///< Assertions outstanding for this pack 219 ast::AssertionSet have; ///< Assertions found for this pack 220 ast::OpenVarSet open; ///< Open variables for this pack 221 unsigned nextArg; ///< Index of next argument in arguments list 222 unsigned tupleStart; ///< Number of tuples that start at this index 223 unsigned nextExpl; ///< Index of next exploded element 224 unsigned explAlt; ///< Index of alternative for nextExpl > 0 225 226 ArgPack() 227 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 228 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 229 230 ArgPack( 231 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 232 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 233 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 234 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 235 236 ArgPack( 237 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 238 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 239 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 240 unsigned nextExpl = 0, unsigned explAlt = 0 ) 241 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ), 242 have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 243 nextExpl( nextExpl ), explAlt( explAlt ) {} 244 245 ArgPack( 246 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 247 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 248 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ), 249 need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), 250 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 251 252 /// true if this pack is in the middle of an exploded argument 253 bool hasExpl() const { return nextExpl > 0; } 254 255 /// Gets the list of exploded candidates for this pack 256 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const { 257 return args[ nextArg-1 ][ explAlt ]; 258 } 259 260 /// Ends a tuple expression, consolidating the appropriate args 261 void endTuple( const std::vector< ArgPack > & packs ) { 262 // add all expressions in tuple to list, summing cost 263 std::deque< const ast::Expr * > exprs; 264 const ArgPack * pack = this; 265 if ( expr ) { exprs.emplace_front( expr ); } 266 while ( pack->tupleStart == 0 ) { 267 pack = &packs[pack->parent]; 268 exprs.emplace_front( pack->expr ); 269 cost += pack->cost; 270 } 271 // reset pack to appropriate tuple 272 std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() ); 273 expr = new ast::TupleExpr{ expr->location, std::move( exprv ) }; 274 tupleStart = pack->tupleStart - 1; 275 parent = pack->parent; 276 } 277 }; 278 279 /// Instantiates an argument to match a parameter, returns false if no matching results left 280 bool instantiateArgument( 281 const CodeLocation & location, 282 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 283 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 284 unsigned nTuples = 0 285 ) { 286 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { 287 // paramType is a TupleType -- group args into a TupleExpr 288 ++nTuples; 289 for ( const ast::Type * type : *tupleType ) { 290 // xxx - dropping initializer changes behaviour from previous, but seems correct 291 // ^^^ need to handle the case where a tuple has a default argument 292 if ( ! instantiateArgument( location, 293 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 294 nTuples = 0; 295 } 296 // re-constitute tuples for final generation 297 for ( auto i = genStart; i < results.size(); ++i ) { 298 results[i].endTuple( results ); 299 } 300 return true; 301 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 302 // paramType is a ttype, consumes all remaining arguments 303 304 // completed tuples; will be spliced to end of results to finish 305 std::vector< ArgPack > finalResults{}; 306 307 // iterate until all results completed 308 std::size_t genEnd; 309 ++nTuples; 310 do { 311 genEnd = results.size(); 312 313 // add another argument to results 314 for ( std::size_t i = genStart; i < genEnd; ++i ) { 315 unsigned nextArg = results[i].nextArg; 316 317 // use next element of exploded tuple if present 318 if ( results[i].hasExpl() ) { 319 const ExplodedArg & expl = results[i].getExpl( args ); 320 321 unsigned nextExpl = results[i].nextExpl + 1; 322 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 323 324 results.emplace_back( 325 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 326 copy( results[i].need ), copy( results[i].have ), 327 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 328 results[i].explAlt ); 329 330 continue; 331 } 332 333 // finish result when out of arguments 334 if ( nextArg >= args.size() ) { 335 ArgPack newResult{ 336 results[i].env, results[i].need, results[i].have, results[i].open }; 337 newResult.nextArg = nextArg; 338 const ast::Type * argType = nullptr; 339 340 if ( nTuples > 0 || ! results[i].expr ) { 341 // first iteration or no expression to clone, 342 // push empty tuple expression 343 newResult.parent = i; 344 newResult.expr = new ast::TupleExpr( location, {} ); 345 argType = newResult.expr->result; 346 } else { 347 // clone result to collect tuple 348 newResult.parent = results[i].parent; 349 newResult.cost = results[i].cost; 350 newResult.tupleStart = results[i].tupleStart; 351 newResult.expr = results[i].expr; 352 argType = newResult.expr->result; 353 354 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) { 355 // the case where a ttype value is passed directly is special, 356 // e.g. for argument forwarding purposes 357 // xxx - what if passing multiple arguments, last of which is 358 // ttype? 359 // xxx - what would happen if unify was changed so that unifying 360 // tuple 361 // types flattened both before unifying lists? then pass in 362 // TupleType (ttype) below. 363 --newResult.tupleStart; 364 } else { 365 // collapse leftover arguments into tuple 366 newResult.endTuple( results ); 367 argType = newResult.expr->result; 368 } 369 } 370 371 // check unification for ttype before adding to final 372 if ( 373 unify( 374 ttype, argType, newResult.env, newResult.need, newResult.have, 375 newResult.open ) 376 ) { 377 finalResults.emplace_back( std::move( newResult ) ); 378 } 379 380 continue; 381 } 382 383 // add each possible next argument 384 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 385 const ExplodedArg & expl = args[nextArg][j]; 386 387 // fresh copies of parent parameters for this iteration 388 ast::TypeEnvironment env = results[i].env; 389 ast::OpenVarSet open = results[i].open; 390 391 env.addActual( expl.env, open ); 392 393 // skip empty tuple arguments by (nearly) cloning parent into next gen 394 if ( expl.exprs.empty() ) { 395 results.emplace_back( 396 results[i], std::move( env ), copy( results[i].need ), 397 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost ); 398 399 continue; 400 } 401 402 // add new result 403 results.emplace_back( 404 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 405 copy( results[i].have ), std::move( open ), nextArg + 1, nTuples, 406 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 407 } 408 } 409 410 // reset for next round 411 genStart = genEnd; 412 nTuples = 0; 413 } while ( genEnd != results.size() ); 414 415 // splice final results onto results 416 for ( std::size_t i = 0; i < finalResults.size(); ++i ) { 417 results.emplace_back( std::move( finalResults[i] ) ); 418 } 419 return ! finalResults.empty(); 420 } 421 422 // iterate each current subresult 423 std::size_t genEnd = results.size(); 424 for ( std::size_t i = genStart; i < genEnd; ++i ) { 425 unsigned nextArg = results[i].nextArg; 426 427 // use remainder of exploded tuple if present 428 if ( results[i].hasExpl() ) { 429 const ExplodedArg & expl = results[i].getExpl( args ); 430 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ]; 431 432 ast::TypeEnvironment env = results[i].env; 433 ast::AssertionSet need = results[i].need, have = results[i].have; 434 ast::OpenVarSet open = results[i].open; 435 436 const ast::Type * argType = expr->result; 437 438 PRINT( 439 std::cerr << "param type is "; 440 ast::print( std::cerr, paramType ); 441 std::cerr << std::endl << "arg type is "; 442 ast::print( std::cerr, argType ); 443 std::cerr << std::endl; 444 ) 445 446 if ( unify( paramType, argType, env, need, have, open ) ) { 447 unsigned nextExpl = results[i].nextExpl + 1; 448 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 449 450 results.emplace_back( 451 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg, 452 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 453 } 454 455 continue; 456 } 457 458 // use default initializers if out of arguments 459 if ( nextArg >= args.size() ) { 460 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) { 461 ast::TypeEnvironment env = results[i].env; 462 ast::AssertionSet need = results[i].need, have = results[i].have; 463 ast::OpenVarSet open = results[i].open; 464 465 if ( unify( paramType, cnst->result, env, need, have, open ) ) { 466 results.emplace_back( 467 i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ), 468 std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples ); 469 } 470 } 471 472 continue; 473 } 474 475 // Check each possible next argument 476 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 477 const ExplodedArg & expl = args[nextArg][j]; 478 479 // fresh copies of parent parameters for this iteration 480 ast::TypeEnvironment env = results[i].env; 481 ast::AssertionSet need = results[i].need, have = results[i].have; 482 ast::OpenVarSet open = results[i].open; 483 484 env.addActual( expl.env, open ); 485 486 // skip empty tuple arguments by (nearly) cloning parent into next gen 487 if ( expl.exprs.empty() ) { 488 results.emplace_back( 489 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ), 490 nextArg + 1, expl.cost ); 491 492 continue; 493 } 494 495 // consider only first exploded arg 496 const ast::Expr * expr = expl.exprs.front(); 497 const ast::Type * argType = expr->result; 498 499 PRINT( 500 std::cerr << "param type is "; 501 ast::print( std::cerr, paramType ); 502 std::cerr << std::endl << "arg type is "; 503 ast::print( std::cerr, argType ); 504 std::cerr << std::endl; 505 ) 506 507 // attempt to unify types 508 if ( unify( paramType, argType, env, need, have, open ) ) { 509 // add new result 510 results.emplace_back( 511 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), 512 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 513 } 514 } 515 } 516 517 // reset for next parameter 518 genStart = genEnd; 519 520 return genEnd != results.size(); // were any new results added? 521 } 522 523 /// Generate a cast expression from `arg` to `toType` 524 const ast::Expr * restructureCast( 525 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 526 ) { 527 if ( 528 arg->result->size() > 1 529 && ! toType->isVoid() 530 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 531 ) { 532 // Argument is a tuple and the target type is neither void nor a reference. Cast each 533 // member of the tuple to its corresponding target type, producing the tuple of those 534 // cast expressions. If there are more components of the tuple than components in the 535 // target type, then excess components do not come out in the result expression (but 536 // UniqueExpr ensures that the side effects will still be produced) 537 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 538 // expressions which may contain side effects require a single unique instance of 539 // the expression 540 arg = new ast::UniqueExpr{ arg->location, arg }; 541 } 542 std::vector< ast::ptr< ast::Expr > > components; 543 for ( unsigned i = 0; i < toType->size(); ++i ) { 544 // cast each component 545 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 546 components.emplace_back( 547 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 548 } 549 return new ast::TupleExpr{ arg->location, std::move( components ) }; 550 } else { 551 // handle normally 552 return new ast::CastExpr{ arg->location, arg, toType, isGenerated }; 553 } 554 } 555 556 /// Gets the name from an untyped member expression (must be NameExpr) 557 const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) { 558 if ( memberExpr->member.as< ast::ConstantExpr >() ) { 559 SemanticError( memberExpr, "Indexed access to struct fields unsupported: " ); 560 } 561 562 return memberExpr->member.strict_as< ast::NameExpr >()->name; 563 } 564 565 /// Actually visits expressions to find their candidate interpretations 566 class Finder final : public ast::WithShortCircuiting { 567 const ResolveContext & context; 568 const ast::SymbolTable & symtab; 569 public: 570 // static size_t traceId; 571 CandidateFinder & selfFinder; 572 CandidateList & candidates; 573 const ast::TypeEnvironment & tenv; 574 ast::ptr< ast::Type > & targetType; 575 576 enum Errors { 577 NotFound, 578 NoMatch, 579 ArgsToFew, 580 ArgsToMany, 581 RetsToFew, 582 RetsToMany, 583 NoReason 584 }; 585 586 struct { 587 Errors code = NotFound; 588 } reason; 589 590 Finder( CandidateFinder & f ) 591 : context( f.context ), symtab( context.symtab ), selfFinder( f ), 592 candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {} 593 594 void previsit( const ast::Node * ) { visit_children = false; } 595 596 /// Convenience to add candidate to list 597 template<typename... Args> 598 void addCandidate( Args &&... args ) { 599 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 600 reason.code = NoReason; 601 } 602 603 void postvisit( const ast::ApplicationExpr * applicationExpr ) { 604 addCandidate( applicationExpr, tenv ); 605 } 606 607 /// Set up candidate assertions for inference 608 void inferParameters( CandidateRef & newCand, CandidateList & out ); 609 610 /// Completes a function candidate with arguments located 611 void validateFunctionCandidate( 612 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 613 CandidateList & out ); 614 615 /// Builds a list of candidates for a function, storing them in out 616 void makeFunctionCandidates( 617 const CodeLocation & location, 618 const CandidateRef & func, const ast::FunctionType * funcType, 619 const ExplodedArgs_new & args, CandidateList & out ); 620 621 /// Adds implicit struct-conversions to the alternative list 622 void addAnonConversions( const CandidateRef & cand ); 623 624 /// Adds aggregate member interpretations 625 void addAggMembers( 626 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 627 const Candidate & cand, const Cost & addedCost, const std::string & name 628 ); 629 630 /// Adds tuple member interpretations 631 void addTupleMembers( 632 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 633 const Cost & addedCost, const ast::Expr * member 634 ); 635 636 /// true if expression is an lvalue 637 static bool isLvalue( const ast::Expr * x ) { 638 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 639 } 640 641 void postvisit( const ast::UntypedExpr * untypedExpr ); 642 void postvisit( const ast::VariableExpr * variableExpr ); 643 void postvisit( const ast::ConstantExpr * constantExpr ); 644 void postvisit( const ast::SizeofExpr * sizeofExpr ); 645 void postvisit( const ast::AlignofExpr * alignofExpr ); 646 void postvisit( const ast::AddressExpr * addressExpr ); 647 void postvisit( const ast::LabelAddressExpr * labelExpr ); 648 void postvisit( const ast::CastExpr * castExpr ); 649 void postvisit( const ast::VirtualCastExpr * castExpr ); 650 void postvisit( const ast::KeywordCastExpr * castExpr ); 651 void postvisit( const ast::UntypedMemberExpr * memberExpr ); 652 void postvisit( const ast::MemberExpr * memberExpr ); 653 void postvisit( const ast::NameExpr * nameExpr ); 654 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ); 655 void postvisit( const ast::OffsetofExpr * offsetofExpr ); 656 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ); 657 void postvisit( const ast::LogicalExpr * logicalExpr ); 658 void postvisit( const ast::ConditionalExpr * conditionalExpr ); 659 void postvisit( const ast::CommaExpr * commaExpr ); 660 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ); 661 void postvisit( const ast::ConstructorExpr * ctorExpr ); 662 void postvisit( const ast::RangeExpr * rangeExpr ); 663 void postvisit( const ast::UntypedTupleExpr * tupleExpr ); 664 void postvisit( const ast::TupleExpr * tupleExpr ); 665 void postvisit( const ast::TupleIndexExpr * tupleExpr ); 666 void postvisit( const ast::TupleAssignExpr * tupleExpr ); 667 void postvisit( const ast::UniqueExpr * unqExpr ); 668 void postvisit( const ast::StmtExpr * stmtExpr ); 669 void postvisit( const ast::UntypedInitExpr * initExpr ); 670 671 void postvisit( const ast::InitExpr * ) { 672 assertf( false, "CandidateFinder should never see a resolved InitExpr." ); 673 } 674 675 void postvisit( const ast::DeletedExpr * ) { 676 assertf( false, "CandidateFinder should never see a DeletedExpr." ); 677 } 678 679 void postvisit( const ast::GenericExpr * ) { 680 assertf( false, "_Generic is not yet supported." ); 681 } 682 }; 683 684 /// Set up candidate assertions for inference 685 void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) { 686 // Set need bindings for any unbound assertions 687 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions 688 for ( auto & assn : newCand->need ) { 689 // skip already-matched assertions 690 if ( assn.second.resnSlot != 0 ) continue; 691 // assign slot for expression if needed 692 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; } 693 // fix slot to assertion 694 assn.second.resnSlot = crntResnSlot; 695 } 696 // pair slot to expression 697 if ( crntResnSlot != 0 ) { 698 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot ); 699 } 700 701 // add to output list; assertion satisfaction will occur later 702 out.emplace_back( newCand ); 703 } 704 705 /// Completes a function candidate with arguments located 706 void Finder::validateFunctionCandidate( 707 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 708 CandidateList & out 709 ) { 710 ast::ApplicationExpr * appExpr = 711 new ast::ApplicationExpr{ func->expr->location, func->expr }; 712 // sum cost and accumulate arguments 713 std::deque< const ast::Expr * > args; 714 Cost cost = func->cost; 715 const ArgPack * pack = &result; 716 while ( pack->expr ) { 717 args.emplace_front( pack->expr ); 718 cost += pack->cost; 719 pack = &results[pack->parent]; 720 } 721 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() ); 722 appExpr->args = std::move( vargs ); 723 // build and validate new candidate 724 auto newCand = 725 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 726 PRINT( 727 std::cerr << "instantiate function success: " << appExpr << std::endl; 728 std::cerr << "need assertions:" << std::endl; 729 ast::print( std::cerr, result.need, 2 ); 730 ) 731 inferParameters( newCand, out ); 732 } 733 734 /// Builds a list of candidates for a function, storing them in out 735 void Finder::makeFunctionCandidates( 736 const CodeLocation & location, 737 const CandidateRef & func, const ast::FunctionType * funcType, 738 const ExplodedArgs_new & args, CandidateList & out 739 ) { 740 ast::OpenVarSet funcOpen; 741 ast::AssertionSet funcNeed, funcHave; 742 ast::TypeEnvironment funcEnv{ func->env }; 743 makeUnifiableVars( funcType, funcOpen, funcNeed ); 744 // add all type variables as open variables now so that those not used in the 745 // parameter list are still considered open 746 funcEnv.add( funcType->forall ); 747 748 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) { 749 // attempt to narrow based on expected target type 750 const ast::Type * returnType = funcType->returns.front(); 751 if ( ! unify( 752 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen ) 753 ) { 754 // unification failed, do not pursue this candidate 755 return; 756 } 757 } 758 759 // iteratively build matches, one parameter at a time 760 std::vector< ArgPack > results; 761 results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen ); 762 std::size_t genStart = 0; 763 764 // xxx - how to handle default arg after change to ftype representation? 765 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) { 766 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) { 767 // function may have default args only if directly calling by name 768 // must use types on candidate however, due to RenameVars substitution 769 auto nParams = funcType->params.size(); 770 771 for (size_t i=0; i<nParams; ++i) { 772 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 773 if (!instantiateArgument( location, 774 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 775 } 776 goto endMatch; 777 } 778 } 779 for ( const auto & param : funcType->params ) { 780 // Try adding the arguments corresponding to the current parameter to the existing 781 // matches 782 // no default args for indirect calls 783 if ( ! instantiateArgument( location, 784 param, nullptr, args, results, genStart, symtab ) ) return; 785 } 786 787 endMatch: 788 if ( funcType->isVarArgs ) { 789 // append any unused arguments to vararg pack 790 std::size_t genEnd; 791 do { 792 genEnd = results.size(); 793 794 // iterate results 795 for ( std::size_t i = genStart; i < genEnd; ++i ) { 796 unsigned nextArg = results[i].nextArg; 797 798 // use remainder of exploded tuple if present 799 if ( results[i].hasExpl() ) { 800 const ExplodedArg & expl = results[i].getExpl( args ); 801 802 unsigned nextExpl = results[i].nextExpl + 1; 803 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 804 805 results.emplace_back( 806 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 807 copy( results[i].need ), copy( results[i].have ), 808 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl, 809 results[i].explAlt ); 810 811 continue; 812 } 813 814 // finish result when out of arguments 815 if ( nextArg >= args.size() ) { 816 validateFunctionCandidate( func, results[i], results, out ); 817 818 continue; 819 } 820 821 // add each possible next argument 822 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 823 const ExplodedArg & expl = args[nextArg][j]; 824 825 // fresh copies of parent parameters for this iteration 826 ast::TypeEnvironment env = results[i].env; 827 ast::OpenVarSet open = results[i].open; 828 829 env.addActual( expl.env, open ); 830 831 // skip empty tuple arguments by (nearly) cloning parent into next gen 832 if ( expl.exprs.empty() ) { 833 results.emplace_back( 834 results[i], std::move( env ), copy( results[i].need ), 835 copy( results[i].have ), std::move( open ), nextArg + 1, 836 expl.cost ); 837 838 continue; 839 } 840 841 // add new result 842 results.emplace_back( 843 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 844 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost, 845 expl.exprs.size() == 1 ? 0 : 1, j ); 846 } 847 } 848 849 genStart = genEnd; 850 } while( genEnd != results.size() ); 851 } else { 852 // filter out the results that don't use all the arguments 853 for ( std::size_t i = genStart; i < results.size(); ++i ) { 854 ArgPack & result = results[i]; 855 if ( ! result.hasExpl() && result.nextArg >= args.size() ) { 856 validateFunctionCandidate( func, result, results, out ); 857 } 858 } 859 } 860 } 861 862 /// Adds implicit struct-conversions to the alternative list 863 void Finder::addAnonConversions( const CandidateRef & cand ) { 864 // adds anonymous member interpretations whenever an aggregate value type is seen. 865 // it's okay for the aggregate expression to have reference type -- cast it to the 866 // base type to treat the aggregate as the referenced value 867 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 868 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 869 cand->env.apply( aggrType ); 870 871 if ( aggrType.as< ast::ReferenceType >() ) { 872 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; 873 } 874 875 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) { 876 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" ); 877 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) { 878 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" ); 879 } 880 } 881 882 /// Adds aggregate member interpretations 883 void Finder::addAggMembers( 884 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 885 const Candidate & cand, const Cost & addedCost, const std::string & name 886 ) { 887 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 888 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 889 CandidateRef newCand = std::make_shared<Candidate>( 890 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 891 // add anonymous member interpretations whenever an aggregate value type is seen 892 // as a member expression 893 addAnonConversions( newCand ); 894 candidates.emplace_back( std::move( newCand ) ); 895 } 896 } 897 898 /// Adds tuple member interpretations 899 void Finder::addTupleMembers( 900 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 901 const Cost & addedCost, const ast::Expr * member 902 ) { 903 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 904 // get the value of the constant expression as an int, must be between 0 and the 905 // length of the tuple to have meaning 906 long long val = constantExpr->intValue(); 907 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 908 addCandidate( 909 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 910 addedCost ); 911 } 912 } 913 } 914 915 void Finder::postvisit( const ast::UntypedExpr * untypedExpr ) { 916 std::vector< CandidateFinder > argCandidates = 917 selfFinder.findSubExprs( untypedExpr->args ); 918 919 // take care of possible tuple assignments 920 // if not tuple assignment, handled as normal function call 921 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates ); 922 923 CandidateFinder funcFinder( context, tenv ); 924 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) { 925 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 926 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) { 927 assertf(!argCandidates.empty(), "special function call without argument"); 928 for (auto & firstArgCand: argCandidates[0]) { 929 ast::ptr<ast::Type> argType = firstArgCand->expr->result; 930 firstArgCand->env.apply(argType); 931 // strip references 932 // xxx - is this correct? 933 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base; 934 935 // convert 1-tuple to plain type 936 if (auto tuple = argType.as<ast::TupleType>()) { 937 if (tuple->size() == 1) { 938 argType = tuple->types[0]; 939 } 940 } 941 942 // if argType is an unbound type parameter, all special functions need to be searched. 943 if (isUnboundType(argType)) { 944 funcFinder.otypeKeys.clear(); 945 break; 946 } 947 948 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer); 949 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) { 950 // const ast::EnumDecl * enumDecl = enumInst->base; // Here 951 // if ( const ast::Type* enumType = enumDecl->base ) { 952 // // instance of enum (T) is a instance of type (T) 953 // funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type)); 954 // } else { 955 // // instance of an untyped enum is techically int 956 // funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type)); 957 // } 958 // } 959 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type)); 960 } 961 } 962 } 963 // if candidates are already produced, do not fail 964 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates? 965 // this means there exists ctor/assign functions with a tuple as first parameter. 966 ResolvMode mode = { 967 true, // adjust 968 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name 969 selfFinder.candidates.empty() // failfast if other options are not found 970 }; 971 funcFinder.find( untypedExpr->func, mode ); 972 // short-circuit if no candidates 973 // if ( funcFinder.candidates.empty() ) return; 974 975 reason.code = NoMatch; 976 977 // find function operators 978 ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{} 979 CandidateFinder opFinder( context, tenv ); 980 // okay if there aren't any function operations 981 opFinder.find( opExpr, ResolvMode::withoutFailFast() ); 982 PRINT( 983 std::cerr << "known function ops:" << std::endl; 984 print( std::cerr, opFinder.candidates, 1 ); 985 ) 986 987 // pre-explode arguments 988 ExplodedArgs_new argExpansions; 989 for ( const CandidateFinder & args : argCandidates ) { 990 argExpansions.emplace_back(); 991 auto & argE = argExpansions.back(); 992 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); } 993 } 994 995 // Find function matches 996 CandidateList found; 997 SemanticErrorException errors; 998 for ( CandidateRef & func : funcFinder ) { 999 try { 1000 PRINT( 1001 std::cerr << "working on alternative:" << std::endl; 1002 print( std::cerr, *func, 2 ); 1003 ) 1004 1005 // check if the type is a pointer to function 1006 const ast::Type * funcResult = func->expr->result->stripReferences(); 1007 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) { 1008 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1009 CandidateRef newFunc{ new Candidate{ *func } }; 1010 newFunc->expr = 1011 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 1012 makeFunctionCandidates( untypedExpr->location, 1013 newFunc, function, argExpansions, found ); 1014 } 1015 } else if ( 1016 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 1017 ) { 1018 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 1019 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 1020 CandidateRef newFunc{ new Candidate{ *func } }; 1021 newFunc->expr = 1022 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 1023 makeFunctionCandidates( untypedExpr->location, 1024 newFunc, function, argExpansions, found ); 1025 } 1026 } 1027 } 1028 } catch ( SemanticErrorException & e ) { errors.append( e ); } 1029 } 1030 1031 // Find matches on function operators `?()` 1032 if ( ! opFinder.candidates.empty() ) { 1033 // add exploded function alternatives to front of argument list 1034 std::vector< ExplodedArg > funcE; 1035 funcE.reserve( funcFinder.candidates.size() ); 1036 for ( const CandidateRef & func : funcFinder ) { 1037 funcE.emplace_back( *func, symtab ); 1038 } 1039 argExpansions.emplace_front( std::move( funcE ) ); 1040 1041 for ( const CandidateRef & op : opFinder ) { 1042 try { 1043 // check if type is pointer-to-function 1044 const ast::Type * opResult = op->expr->result->stripReferences(); 1045 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) { 1046 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1047 CandidateRef newOp{ new Candidate{ *op} }; 1048 newOp->expr = 1049 referenceToRvalueConversion( newOp->expr, newOp->cost ); 1050 makeFunctionCandidates( untypedExpr->location, 1051 newOp, function, argExpansions, found ); 1052 } 1053 } 1054 } catch ( SemanticErrorException & e ) { errors.append( e ); } 1055 } 1056 } 1057 1058 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 1059 // candidates 1060 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } 1061 1062 // Compute conversion costs 1063 for ( CandidateRef & withFunc : found ) { 1064 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab ); 1065 1066 PRINT( 1067 auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >(); 1068 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 1069 auto function = pointer->base.strict_as< ast::FunctionType >(); 1070 1071 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 1072 std::cerr << "parameters are:" << std::endl; 1073 ast::printAll( std::cerr, function->params, 2 ); 1074 std::cerr << "arguments are:" << std::endl; 1075 ast::printAll( std::cerr, appExpr->args, 2 ); 1076 std::cerr << "bindings are:" << std::endl; 1077 ast::print( std::cerr, withFunc->env, 2 ); 1078 std::cerr << "cost is: " << withFunc->cost << std::endl; 1079 std::cerr << "cost of conversion is:" << cvtCost << std::endl; 1080 ) 1081 1082 if ( cvtCost != Cost::infinity ) { 1083 withFunc->cvtCost = cvtCost; 1084 candidates.emplace_back( std::move( withFunc ) ); 1085 } 1086 } 1087 found = std::move( candidates ); 1088 1089 // use a new list so that candidates are not examined by addAnonConversions twice 1090 CandidateList winners = findMinCost( found ); 1091 promoteCvtCost( winners ); 1092 1093 // function may return a struct/union value, in which case we need to add candidates 1094 // for implicit conversions to each of the anonymous members, which must happen after 1095 // `findMinCost`, since anon conversions are never the cheapest 1096 for ( const CandidateRef & c : winners ) { 1097 addAnonConversions( c ); 1098 } 1099 spliceBegin( candidates, winners ); 1100 1101 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 1102 // If resolution is unsuccessful with a target type, try again without, since it 1103 // will sometimes succeed when it wouldn't with a target type binding. 1104 // For example: 1105 // forall( otype T ) T & ?[]( T *, ptrdiff_t ); 1106 // const char * x = "hello world"; 1107 // unsigned char ch = x[0]; 1108 // Fails with simple return type binding (xxx -- check this!) as follows: 1109 // * T is bound to unsigned char 1110 // * (x: const char *) is unified with unsigned char *, which fails 1111 // xxx -- fix this better 1112 targetType = nullptr; 1113 postvisit( untypedExpr ); 1114 } 1115 } 1116 1117 void Finder::postvisit( const ast::AddressExpr * addressExpr ) { 1118 CandidateFinder finder( context, tenv ); 1119 finder.find( addressExpr->arg ); 1120 1121 if ( finder.candidates.empty() ) return; 1122 1123 reason.code = NoMatch; 1124 1125 for ( CandidateRef & r : finder.candidates ) { 1126 if ( ! isLvalue( r->expr ) ) continue; 1127 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } ); 1128 } 1129 } 1130 1131 void Finder::postvisit( const ast::LabelAddressExpr * labelExpr ) { 1132 addCandidate( labelExpr, tenv ); 1133 } 1134 1135 void Finder::postvisit( const ast::CastExpr * castExpr ) { 1136 ast::ptr< ast::Type > toType = castExpr->result; 1137 assert( toType ); 1138 toType = resolveTypeof( toType, context ); 1139 toType = adjustExprType( toType, tenv, symtab ); 1140 1141 CandidateFinder finder( context, tenv, toType ); 1142 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1143 1144 if ( !finder.candidates.empty() ) reason.code = NoMatch; 1145 1146 CandidateList matches; 1147 for ( CandidateRef & cand : finder.candidates ) { 1148 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; 1149 ast::OpenVarSet open( cand->open ); 1150 1151 cand->env.extractOpenVars( open ); 1152 1153 // It is possible that a cast can throw away some values in a multiply-valued 1154 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1155 // subexpression results that are cast directly. The candidate is invalid if it 1156 // has fewer results than there are types to cast to. 1157 int discardedValues = cand->expr->result->size() - toType->size(); 1158 if ( discardedValues < 0 ) continue; 1159 1160 // unification run for side-effects 1161 unify( toType, cand->expr->result, cand->env, need, have, open ); 1162 Cost thisCost = 1163 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast) 1164 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ) 1165 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ); 1166 1167 PRINT( 1168 std::cerr << "working on cast with result: " << toType << std::endl; 1169 std::cerr << "and expr type: " << cand->expr->result << std::endl; 1170 std::cerr << "env: " << cand->env << std::endl; 1171 ) 1172 if ( thisCost != Cost::infinity ) { 1173 PRINT( 1174 std::cerr << "has finite cost." << std::endl; 1175 ) 1176 // count one safe conversion for each value that is thrown away 1177 thisCost.incSafe( discardedValues ); 1178 CandidateRef newCand = std::make_shared<Candidate>( 1179 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1180 copy( cand->env ), std::move( open ), std::move( need ), cand->cost, 1181 cand->cost + thisCost ); 1182 inferParameters( newCand, matches ); 1183 } 1184 } 1185 1186 // select first on argument cost, then conversion cost 1187 CandidateList minArgCost = findMinCost( matches ); 1188 promoteCvtCost( minArgCost ); 1189 candidates = findMinCost( minArgCost ); 1190 } 1191 1192 void Finder::postvisit( const ast::VirtualCastExpr * castExpr ) { 1193 assertf( castExpr->result, "Implicit virtual cast targets not yet supported." ); 1194 CandidateFinder finder( context, tenv ); 1195 // don't prune here, all alternatives guaranteed to have same type 1196 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1197 for ( CandidateRef & r : finder.candidates ) { 1198 addCandidate( 1199 *r, 1200 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1201 } 1202 } 1203 1204 void Finder::postvisit( const ast::KeywordCastExpr * castExpr ) { 1205 const auto & loc = castExpr->location; 1206 assertf( castExpr->result, "Cast target should have been set in Validate." ); 1207 auto ref = castExpr->result.strict_as<ast::ReferenceType>(); 1208 auto inst = ref->base.strict_as<ast::StructInstType>(); 1209 auto target = inst->base.get(); 1210 1211 CandidateFinder finder( context, tenv ); 1212 1213 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) { 1214 for (auto & cand : found) { 1215 const ast::Type * expr = cand->expr->result.get(); 1216 if (expect_ref) { 1217 auto res = dynamic_cast<const ast::ReferenceType*>(expr); 1218 if (!res) { continue; } 1219 expr = res->base.get(); 1220 } 1221 1222 if (auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) { 1223 auto td = cand->env.lookup(*insttype); 1224 if (!td) { continue; } 1225 expr = td->bound.get(); 1226 } 1227 1228 if (auto base = dynamic_cast<const ast::StructInstType*>(expr)) { 1229 if (base->base == target) { 1230 candidates.push_back( std::move(cand) ); 1231 reason.code = NoReason; 1232 } 1233 } 1234 } 1235 }; 1236 1237 try { 1238 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd 1239 // Clone is purely for memory management 1240 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) }; 1241 1242 // don't prune here, since it's guaranteed all alternatives will have the same type 1243 finder.find( tech1.get(), ResolvMode::withoutPrune() ); 1244 pick_alternatives(finder.candidates, false); 1245 1246 return; 1247 } catch(SemanticErrorException & ) {} 1248 1249 // Fallback : turn (thread&)X into (thread$&)get_thread(X) 1250 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) }; 1251 // don't prune here, since it's guaranteed all alternatives will have the same type 1252 finder.find( fallback.get(), ResolvMode::withoutPrune() ); 1253 1254 pick_alternatives(finder.candidates, true); 1255 1256 // Whatever happens here, we have no more fallbacks 1257 } 1258 1259 void Finder::postvisit( const ast::UntypedMemberExpr * memberExpr ) { 1260 CandidateFinder aggFinder( context, tenv ); 1261 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1262 for ( CandidateRef & agg : aggFinder.candidates ) { 1263 // it's okay for the aggregate expression to have reference type -- cast it to the 1264 // base type to treat the aggregate as the referenced value 1265 Cost addedCost = Cost::zero; 1266 agg->expr = referenceToRvalueConversion( agg->expr, addedCost ); 1267 1268 // find member of the given type 1269 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1270 addAggMembers( 1271 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1272 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1273 addAggMembers( 1274 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1275 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { 1276 addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member ); 1277 } 1278 } 1279 } 1280 1281 void Finder::postvisit( const ast::MemberExpr * memberExpr ) { 1282 addCandidate( memberExpr, tenv ); 1283 } 1284 1285 void Finder::postvisit( const ast::NameExpr * nameExpr ) { 1286 std::vector< ast::SymbolTable::IdData > declList; 1287 if (!selfFinder.otypeKeys.empty()) { 1288 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 1289 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str()); 1290 1291 for (auto & otypeKey: selfFinder.otypeKeys) { 1292 auto result = symtab.specialLookupId(kind, otypeKey); 1293 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end())); 1294 } 1295 } else { 1296 declList = symtab.lookupId( nameExpr->name ); 1297 } 1298 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1299 1300 if ( declList.empty() ) return; 1301 1302 reason.code = NoMatch; 1303 1304 for ( auto & data : declList ) { 1305 Cost cost = Cost::zero; 1306 ast::Expr * newExpr = data.combine( nameExpr->location, cost ); 1307 1308 CandidateRef newCand = std::make_shared<Candidate>( 1309 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1310 cost ); 1311 1312 if (newCand->expr->env) { 1313 newCand->env.add(*newCand->expr->env); 1314 auto mutExpr = newCand->expr.get_and_mutate(); 1315 mutExpr->env = nullptr; 1316 newCand->expr = mutExpr; 1317 } 1318 1319 PRINT( 1320 std::cerr << "decl is "; 1321 ast::print( std::cerr, data.id ); 1322 std::cerr << std::endl; 1323 std::cerr << "newExpr is "; 1324 ast::print( std::cerr, newExpr ); 1325 std::cerr << std::endl; 1326 ) 1327 newCand->expr = ast::mutate_field( 1328 newCand->expr.get(), &ast::Expr::result, 1329 renameTyVars( newCand->expr->result ) ); 1330 // add anonymous member interpretations whenever an aggregate value type is seen 1331 // as a name expression 1332 addAnonConversions( newCand ); 1333 candidates.emplace_back( std::move( newCand ) ); 1334 } 1335 } 1336 1337 void Finder::postvisit( const ast::VariableExpr * variableExpr ) { 1338 // not sufficient to just pass `variableExpr` here, type might have changed since 1339 // creation 1340 addCandidate( 1341 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1342 } 1343 1344 void Finder::postvisit( const ast::ConstantExpr * constantExpr ) { 1345 addCandidate( constantExpr, tenv ); 1346 } 1347 1348 void Finder::postvisit( const ast::SizeofExpr * sizeofExpr ) { 1349 if ( sizeofExpr->type ) { 1350 addCandidate( 1351 new ast::SizeofExpr{ 1352 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) }, 1353 tenv ); 1354 } else { 1355 // find all candidates for the argument to sizeof 1356 CandidateFinder finder( context, tenv ); 1357 finder.find( sizeofExpr->expr ); 1358 // find the lowest-cost candidate, otherwise ambiguous 1359 CandidateList winners = findMinCost( finder.candidates ); 1360 if ( winners.size() != 1 ) { 1361 SemanticError( 1362 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1363 } 1364 // return the lowest-cost candidate 1365 CandidateRef & choice = winners.front(); 1366 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1367 choice->cost = Cost::zero; 1368 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } ); 1369 } 1370 } 1371 1372 void Finder::postvisit( const ast::AlignofExpr * alignofExpr ) { 1373 if ( alignofExpr->type ) { 1374 addCandidate( 1375 new ast::AlignofExpr{ 1376 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) }, 1377 tenv ); 1378 } else { 1379 // find all candidates for the argument to alignof 1380 CandidateFinder finder( context, tenv ); 1381 finder.find( alignofExpr->expr ); 1382 // find the lowest-cost candidate, otherwise ambiguous 1383 CandidateList winners = findMinCost( finder.candidates ); 1384 if ( winners.size() != 1 ) { 1385 SemanticError( 1386 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1387 } 1388 // return the lowest-cost candidate 1389 CandidateRef & choice = winners.front(); 1390 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1391 choice->cost = Cost::zero; 1392 addCandidate( 1393 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1394 } 1395 } 1396 1397 void Finder::postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) { 1398 const ast::BaseInstType * aggInst; 1399 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ; 1400 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ; 1401 else return; 1402 1403 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1404 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1405 addCandidate( 1406 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1407 } 1408 } 1409 1410 void Finder::postvisit( const ast::OffsetofExpr * offsetofExpr ) { 1411 addCandidate( offsetofExpr, tenv ); 1412 } 1413 1414 void Finder::postvisit( const ast::OffsetPackExpr * offsetPackExpr ) { 1415 addCandidate( offsetPackExpr, tenv ); 1416 } 1417 1418 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1419 CandidateFinder finder1( context, tenv ); 1420 finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() ); 1421 if ( finder1.candidates.empty() ) return; 1422 1423 CandidateFinder finder2( context, tenv ); 1424 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1425 if ( finder2.candidates.empty() ) return; 1426 1427 reason.code = NoMatch; 1428 1429 for ( const CandidateRef & r1 : finder1.candidates ) { 1430 for ( const CandidateRef & r2 : finder2.candidates ) { 1431 ast::TypeEnvironment env{ r1->env }; 1432 env.simpleCombine( r2->env ); 1433 ast::OpenVarSet open{ r1->open }; 1434 mergeOpenVars( open, r2->open ); 1435 ast::AssertionSet need; 1436 mergeAssertionSet( need, r1->need ); 1437 mergeAssertionSet( need, r2->need ); 1438 1439 addCandidate( 1440 new ast::LogicalExpr{ 1441 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1442 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost ); 1443 } 1444 } 1445 } 1446 1447 void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) { 1448 // candidates for condition 1449 CandidateFinder finder1( context, tenv ); 1450 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() ); 1451 if ( finder1.candidates.empty() ) return; 1452 1453 // candidates for true result 1454 CandidateFinder finder2( context, tenv ); 1455 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() ); 1456 if ( finder2.candidates.empty() ) return; 1457 1458 // candidates for false result 1459 CandidateFinder finder3( context, tenv ); 1460 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1461 if ( finder3.candidates.empty() ) return; 1462 1463 reason.code = NoMatch; 1464 1465 for ( const CandidateRef & r1 : finder1.candidates ) { 1466 for ( const CandidateRef & r2 : finder2.candidates ) { 1467 for ( const CandidateRef & r3 : finder3.candidates ) { 1468 ast::TypeEnvironment env{ r1->env }; 1469 env.simpleCombine( r2->env ); 1470 env.simpleCombine( r3->env ); 1471 ast::OpenVarSet open{ r1->open }; 1472 mergeOpenVars( open, r2->open ); 1473 mergeOpenVars( open, r3->open ); 1474 ast::AssertionSet need; 1475 mergeAssertionSet( need, r1->need ); 1476 mergeAssertionSet( need, r2->need ); 1477 mergeAssertionSet( need, r3->need ); 1478 ast::AssertionSet have; 1479 1480 // unify true and false results, then infer parameters to produce new 1481 // candidates 1482 ast::ptr< ast::Type > common; 1483 if ( 1484 unify( 1485 r2->expr->result, r3->expr->result, env, need, have, open, 1486 common ) 1487 ) { 1488 // generate typed expression 1489 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1490 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1491 newExpr->result = common ? common : r2->expr->result; 1492 // convert both options to result type 1493 Cost cost = r1->cost + r2->cost + r3->cost; 1494 newExpr->arg2 = computeExpressionConversionCost( 1495 newExpr->arg2, newExpr->result, symtab, env, cost ); 1496 newExpr->arg3 = computeExpressionConversionCost( 1497 newExpr->arg3, newExpr->result, symtab, env, cost ); 1498 // output candidate 1499 CandidateRef newCand = std::make_shared<Candidate>( 1500 newExpr, std::move( env ), std::move( open ), std::move( need ), cost ); 1501 inferParameters( newCand, candidates ); 1502 } 1503 } 1504 } 1505 } 1506 } 1507 1508 void Finder::postvisit( const ast::CommaExpr * commaExpr ) { 1509 ast::TypeEnvironment env{ tenv }; 1510 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env ); 1511 1512 CandidateFinder finder2( context, env ); 1513 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); 1514 1515 for ( const CandidateRef & r2 : finder2.candidates ) { 1516 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } ); 1517 } 1518 } 1519 1520 void Finder::postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) { 1521 addCandidate( ctorExpr, tenv ); 1522 } 1523 1524 void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) { 1525 CandidateFinder finder( context, tenv ); 1526 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() ); 1527 for ( CandidateRef & r : finder.candidates ) { 1528 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } ); 1529 } 1530 } 1531 1532 void Finder::postvisit( const ast::RangeExpr * rangeExpr ) { 1533 // resolve low and high, accept candidates where low and high types unify 1534 CandidateFinder finder1( context, tenv ); 1535 finder1.find( rangeExpr->low, ResolvMode::withAdjustment() ); 1536 if ( finder1.candidates.empty() ) return; 1537 1538 CandidateFinder finder2( context, tenv ); 1539 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1540 if ( finder2.candidates.empty() ) return; 1541 1542 reason.code = NoMatch; 1543 1544 for ( const CandidateRef & r1 : finder1.candidates ) { 1545 for ( const CandidateRef & r2 : finder2.candidates ) { 1546 ast::TypeEnvironment env{ r1->env }; 1547 env.simpleCombine( r2->env ); 1548 ast::OpenVarSet open{ r1->open }; 1549 mergeOpenVars( open, r2->open ); 1550 ast::AssertionSet need; 1551 mergeAssertionSet( need, r1->need ); 1552 mergeAssertionSet( need, r2->need ); 1553 ast::AssertionSet have; 1554 1555 ast::ptr< ast::Type > common; 1556 if ( 1557 unify( 1558 r1->expr->result, r2->expr->result, env, need, have, open, 1559 common ) 1560 ) { 1561 // generate new expression 1562 ast::RangeExpr * newExpr = 1563 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1564 newExpr->result = common ? common : r1->expr->result; 1565 // add candidate 1566 CandidateRef newCand = std::make_shared<Candidate>( 1567 newExpr, std::move( env ), std::move( open ), std::move( need ), 1568 r1->cost + r2->cost ); 1569 inferParameters( newCand, candidates ); 1570 } 1571 } 1572 } 1573 } 1574 1575 void Finder::postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1576 std::vector< CandidateFinder > subCandidates = 1577 selfFinder.findSubExprs( tupleExpr->exprs ); 1578 std::vector< CandidateList > possibilities; 1579 combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) ); 1580 1581 for ( const CandidateList & subs : possibilities ) { 1582 std::vector< ast::ptr< ast::Expr > > exprs; 1583 exprs.reserve( subs.size() ); 1584 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); } 1585 1586 ast::TypeEnvironment env; 1587 ast::OpenVarSet open; 1588 ast::AssertionSet need; 1589 for ( const CandidateRef & sub : subs ) { 1590 env.simpleCombine( sub->env ); 1591 mergeOpenVars( open, sub->open ); 1592 mergeAssertionSet( need, sub->need ); 1593 } 1594 1595 addCandidate( 1596 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) }, 1597 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) ); 1598 } 1599 } 1600 1601 void Finder::postvisit( const ast::TupleExpr * tupleExpr ) { 1602 addCandidate( tupleExpr, tenv ); 1603 } 1604 1605 void Finder::postvisit( const ast::TupleIndexExpr * tupleExpr ) { 1606 addCandidate( tupleExpr, tenv ); 1607 } 1608 1609 void Finder::postvisit( const ast::TupleAssignExpr * tupleExpr ) { 1610 addCandidate( tupleExpr, tenv ); 1611 } 1612 1613 void Finder::postvisit( const ast::UniqueExpr * unqExpr ) { 1614 CandidateFinder finder( context, tenv ); 1615 finder.find( unqExpr->expr, ResolvMode::withAdjustment() ); 1616 for ( CandidateRef & r : finder.candidates ) { 1617 // ensure that the the id is passed on so that the expressions are "linked" 1618 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } ); 1619 } 1620 } 1621 1622 void Finder::postvisit( const ast::StmtExpr * stmtExpr ) { 1623 addCandidate( resolveStmtExpr( stmtExpr, context ), tenv ); 1624 } 1625 1626 void Finder::postvisit( const ast::UntypedInitExpr * initExpr ) { 1627 // handle each option like a cast 1628 CandidateList matches; 1629 PRINT( 1630 std::cerr << "untyped init expr: " << initExpr << std::endl; 1631 ) 1632 // O(n^2) checks of d-types with e-types 1633 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) { 1634 // calculate target type 1635 const ast::Type * toType = resolveTypeof( initAlt.type, context ); 1636 toType = adjustExprType( toType, tenv, symtab ); 1637 // The call to find must occur inside this loop, otherwise polymorphic return 1638 // types are not bound to the initialization type, since return type variables are 1639 // only open for the duration of resolving the UntypedExpr. 1640 CandidateFinder finder( context, tenv, toType ); 1641 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1642 for ( CandidateRef & cand : finder.candidates ) { 1643 if (reason.code == NotFound) reason.code = NoMatch; 1644 1645 ast::TypeEnvironment env{ cand->env }; 1646 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; 1647 ast::OpenVarSet open{ cand->open }; 1648 1649 PRINT( 1650 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; 1651 ) 1652 1653 // It is possible that a cast can throw away some values in a multiply-valued 1654 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1655 // the subexpression results that are cast directly. The candidate is invalid 1656 // if it has fewer results than there are types to cast to. 1657 int discardedValues = cand->expr->result->size() - toType->size(); 1658 if ( discardedValues < 0 ) continue; 1659 1660 // unification run for side-effects 1661 bool canUnify = unify( toType, cand->expr->result, env, need, have, open ); 1662 (void) canUnify; 1663 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1664 symtab, env ); 1665 PRINT( 1666 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1667 symtab, env ); 1668 std::cerr << "Considering initialization:"; 1669 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl; 1670 std::cerr << std::endl << " TO: " << toType << std::endl; 1671 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed"); 1672 std::cerr << std::endl << " Legacy cost " << legacyCost; 1673 std::cerr << std::endl << " New cost " << thisCost; 1674 std::cerr << std::endl; 1675 ) 1676 if ( thisCost != Cost::infinity ) { 1677 // count one safe conversion for each value that is thrown away 1678 thisCost.incSafe( discardedValues ); 1679 CandidateRef newCand = std::make_shared<Candidate>( 1680 new ast::InitExpr{ 1681 initExpr->location, restructureCast( cand->expr, toType ), 1682 initAlt.designation }, 1683 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost ); 1684 inferParameters( newCand, matches ); 1685 } 1686 } 1687 } 1688 1689 // select first on argument cost, then conversion cost 1690 CandidateList minArgCost = findMinCost( matches ); 1691 promoteCvtCost( minArgCost ); 1692 candidates = findMinCost( minArgCost ); 1693 } 1694 1695 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder"); 1696 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1697 /// return type. Skips ambiguous candidates. 1698 1699 } // anonymous namespace 1700 1701 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) { 1702 struct PruneStruct { 1703 CandidateRef candidate; 1704 bool ambiguous; 1705 1706 PruneStruct() = default; 1707 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1708 }; 1709 1710 // find lowest-cost candidate for each type 1711 std::unordered_map< std::string, PruneStruct > selected; 1712 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found 1713 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;}); 1714 for ( CandidateRef & candidate : candidates ) { 1715 std::string mangleName; 1716 { 1717 ast::ptr< ast::Type > newType = candidate->expr->result; 1718 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1719 candidate->env.apply( newType ); 1720 mangleName = Mangle::mangle( newType ); 1721 } 1722 1723 auto found = selected.find( mangleName ); 1724 if (found != selected.end() && found->second.candidate->cost < candidate->cost) { 1725 PRINT( 1726 std::cerr << "cost " << candidate->cost << " loses to " 1727 << found->second.candidate->cost << std::endl; 1728 ) 1729 continue; 1730 } 1731 1732 // xxx - when do satisfyAssertions produce more than 1 result? 1733 // this should only happen when initial result type contains 1734 // unbound type parameters, then it should never be pruned by 1735 // the previous step, since renameTyVars guarantees the mangled name 1736 // is unique. 1737 CandidateList satisfied; 1738 bool needRecomputeKey = false; 1739 if (candidate->need.empty()) { 1740 satisfied.emplace_back(candidate); 1741 } 1742 else { 1743 satisfyAssertions(candidate, context.symtab, satisfied, errors); 1744 needRecomputeKey = true; 1745 } 1746 1747 for (auto & newCand : satisfied) { 1748 // recomputes type key, if satisfyAssertions changed it 1749 if (needRecomputeKey) 1750 { 1751 ast::ptr< ast::Type > newType = newCand->expr->result; 1752 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get()); 1753 newCand->env.apply( newType ); 1754 mangleName = Mangle::mangle( newType ); 1755 } 1756 auto found = selected.find( mangleName ); 1757 if ( found != selected.end() ) { 1758 if ( newCand->cost < found->second.candidate->cost ) { 1759 PRINT( 1760 std::cerr << "cost " << newCand->cost << " beats " 1761 << found->second.candidate->cost << std::endl; 1762 ) 1763 1764 found->second = PruneStruct{ newCand }; 1765 } else if ( newCand->cost == found->second.candidate->cost ) { 1766 // if one of the candidates contains a deleted identifier, can pick the other, 1767 // since deleted expressions should not be ambiguous if there is another option 1768 // that is at least as good 1769 if ( findDeletedExpr( newCand->expr ) ) { 1770 // do nothing 1771 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 1772 } else if ( findDeletedExpr( found->second.candidate->expr ) ) { 1773 PRINT( std::cerr << "current is deleted" << std::endl; ) 1774 found->second = PruneStruct{ newCand }; 1775 } else { 1776 PRINT( std::cerr << "marking ambiguous" << std::endl; ) 1777 found->second.ambiguous = true; 1778 } 1779 } else { 1780 // xxx - can satisfyAssertions increase the cost? 1781 PRINT( 1782 std::cerr << "cost " << newCand->cost << " loses to " 1783 << found->second.candidate->cost << std::endl; 1784 ) 1785 } 1786 } else { 1787 selected.emplace_hint( found, mangleName, newCand ); 1788 } 1789 } 1790 } 1791 1792 // report unambiguous min-cost candidates 1793 // CandidateList out; 1794 for ( auto & target : selected ) { 1795 if ( target.second.ambiguous ) continue; 1796 1797 CandidateRef cand = target.second.candidate; 1798 1799 ast::ptr< ast::Type > newResult = cand->expr->result; 1800 cand->env.applyFree( newResult ); 1801 cand->expr = ast::mutate_field( 1802 cand->expr.get(), &ast::Expr::result, std::move( newResult ) ); 1803 1804 out.emplace_back( cand ); 1805 } 1806 // if everything is lost in satisfyAssertions, report the error 1807 return !selected.empty(); 1808 } 1809 1810 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) { 1811 // Find alternatives for expression 1812 ast::Pass<Finder> finder{ *this }; 1813 expr->accept( finder ); 1814 1815 if ( mode.failFast && candidates.empty() ) { 1816 switch(finder.core.reason.code) { 1817 case Finder::NotFound: 1818 { SemanticError( expr, "No alternatives for expression " ); break; } 1819 case Finder::NoMatch: 1820 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1821 case Finder::ArgsToFew: 1822 case Finder::ArgsToMany: 1823 case Finder::RetsToFew: 1824 case Finder::RetsToMany: 1825 case Finder::NoReason: 1826 default: 1827 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1828 } 1829 } 1830 1831 /* 1832 if ( mode.satisfyAssns || mode.prune ) { 1833 // trim candidates to just those where the assertions are satisfiable 1834 // - necessary pre-requisite to pruning 1835 CandidateList satisfied; 1836 std::vector< std::string > errors; 1837 for ( CandidateRef & candidate : candidates ) { 1838 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1839 } 1840 1841 // fail early if none such 1842 if ( mode.failFast && satisfied.empty() ) { 1843 std::ostringstream stream; 1844 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1845 for ( const auto& err : errors ) { 1846 stream << err; 1847 } 1848 SemanticError( expr->location, stream.str() ); 1849 } 1850 1851 // reset candidates 1852 candidates = move( satisfied ); 1853 } 1854 */ 1855 1856 if ( mode.prune ) { 1857 // trim candidates to single best one 1858 PRINT( 1859 std::cerr << "alternatives before prune:" << std::endl; 1860 print( std::cerr, candidates ); 1861 ) 1862 1863 CandidateList pruned; 1864 std::vector<std::string> errors; 1865 bool found = pruneCandidates( candidates, pruned, errors ); 1866 1867 if ( mode.failFast && pruned.empty() ) { 1868 std::ostringstream stream; 1869 if (found) { 1870 CandidateList winners = findMinCost( candidates ); 1871 stream << "Cannot choose between " << winners.size() << " alternatives for " 1872 "expression\n"; 1873 ast::print( stream, expr ); 1874 stream << " Alternatives are:\n"; 1875 print( stream, winners, 1 ); 1876 SemanticError( expr->location, stream.str() ); 1877 } 1878 else { 1879 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1880 for ( const auto& err : errors ) { 1881 stream << err; 1882 } 1883 SemanticError( expr->location, stream.str() ); 1884 } 1885 } 1886 1887 auto oldsize = candidates.size(); 1888 candidates = std::move( pruned ); 1889 1890 PRINT( 1891 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl; 1892 ) 1893 PRINT( 1894 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1895 << std::endl; 1896 ) 1897 } 1898 1899 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1900 // adjusted 1901 if ( mode.adjust ) { 1902 for ( CandidateRef & r : candidates ) { 1903 r->expr = ast::mutate_field( 1904 r->expr.get(), &ast::Expr::result, 1905 adjustExprType( r->expr->result, r->env, context.symtab ) ); 1906 } 1907 } 1908 1909 // Central location to handle gcc extension keyword, etc. for all expressions 1910 for ( CandidateRef & r : candidates ) { 1911 if ( r->expr->extension != expr->extension ) { 1912 r->expr.get_and_mutate()->extension = expr->extension; 1913 } 1914 } 1915 } 1916 1917 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1918 const std::vector< ast::ptr< ast::Expr > > & xs 1919 ) { 1920 std::vector< CandidateFinder > out; 1921 1922 for ( const auto & x : xs ) { 1923 out.emplace_back( context, env ); 1924 out.back().find( x, ResolvMode::withAdjustment() ); 1925 1926 PRINT( 1927 std::cerr << "findSubExprs" << std::endl; 1928 print( std::cerr, out.back().candidates ); 1929 ) 1930 } 1931 1932 return out; 1933 } 1934 53 1935 const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) { 54 1936 if ( expr->result.as< ast::ReferenceType >() ) { … … 60 1942 return expr; 61 1943 } 62 63 /// Unique identifier for matching expression resolutions to their requesting expression64 UniqueId globalResnSlot = 0;65 1944 66 1945 Cost computeConversionCost( … … 89 1968 } 90 1969 91 namespace {92 /// First index is which argument, second is which alternative, third is which exploded element93 using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;94 95 /// Returns a list of alternatives with the minimum cost in the given list96 CandidateList findMinCost( const CandidateList & candidates ) {97 CandidateList out;98 Cost minCost = Cost::infinity;99 for ( const CandidateRef & r : candidates ) {100 if ( r->cost < minCost ) {101 minCost = r->cost;102 out.clear();103 out.emplace_back( r );104 } else if ( r->cost == minCost ) {105 out.emplace_back( r );106 }107 }108 return out;109 }110 111 /// Computes conversion cost for a given expression to a given type112 const ast::Expr * computeExpressionConversionCost(113 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost114 ) {115 Cost convCost = computeConversionCost(116 arg->result, paramType, arg->get_lvalue(), symtab, env );117 outCost += convCost;118 119 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires120 // conversion. Ignore poly cost for now, since this requires resolution of the cast to121 // infer parameters and this does not currently work for the reason stated below122 Cost tmpCost = convCost;123 tmpCost.incPoly( -tmpCost.get_polyCost() );124 if ( tmpCost != Cost::zero ) {125 ast::ptr< ast::Type > newType = paramType;126 env.apply( newType );127 return new ast::CastExpr{ arg, newType };128 129 // xxx - *should* be able to resolve this cast, but at the moment pointers are not130 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,131 // once this is fixed it should be possible to resolve the cast.132 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,133 // but it shouldn't be because this makes the conversion from DT* to DT* since134 // commontype(zero_t, DT*) is DT*, rather than nothing135 136 // CandidateFinder finder{ symtab, env };137 // finder.find( arg, ResolvMode::withAdjustment() );138 // assertf( finder.candidates.size() > 0,139 // "Somehow castable expression failed to find alternatives." );140 // assertf( finder.candidates.size() == 1,141 // "Somehow got multiple alternatives for known cast expression." );142 // return finder.candidates.front()->expr;143 }144 145 return arg;146 }147 148 /// Computes conversion cost for a given candidate149 Cost computeApplicationConversionCost(150 CandidateRef cand, const ast::SymbolTable & symtab151 ) {152 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();153 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();154 auto function = pointer->base.strict_as< ast::FunctionType >();155 156 Cost convCost = Cost::zero;157 const auto & params = function->params;158 auto param = params.begin();159 auto & args = appExpr->args;160 161 for ( unsigned i = 0; i < args.size(); ++i ) {162 const ast::Type * argType = args[i]->result;163 PRINT(164 std::cerr << "arg expression:" << std::endl;165 ast::print( std::cerr, args[i], 2 );166 std::cerr << "--- results are" << std::endl;167 ast::print( std::cerr, argType, 2 );168 )169 170 if ( param == params.end() ) {171 if ( function->isVarArgs ) {172 convCost.incUnsafe();173 PRINT( std::cerr << "end of params with varargs function: inc unsafe: "174 << convCost << std::endl; ; )175 // convert reference-typed expressions into value-typed expressions176 cand->expr = ast::mutate_field_index(177 appExpr, &ast::ApplicationExpr::args, i,178 referenceToRvalueConversion( args[i], convCost ) );179 continue;180 } else return Cost::infinity;181 }182 183 if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {184 // Default arguments should be free - don't include conversion cost.185 // Unwrap them here because they are not relevant to the rest of the system186 cand->expr = ast::mutate_field_index(187 appExpr, &ast::ApplicationExpr::args, i, def->expr );188 ++param;189 continue;190 }191 192 // mark conversion cost and also specialization cost of param type193 // const ast::Type * paramType = (*param)->get_type();194 cand->expr = ast::mutate_field_index(195 appExpr, &ast::ApplicationExpr::args, i,196 computeExpressionConversionCost(197 args[i], *param, symtab, cand->env, convCost ) );198 convCost.decSpec( specCost( *param ) );199 ++param; // can't be in for-loop update because of the continue200 }201 202 if ( param != params.end() ) return Cost::infinity;203 204 // specialization cost of return types can't be accounted for directly, it disables205 // otherwise-identical calls, like this example based on auto-newline in the I/O lib:206 //207 // forall(otype OS) {208 // void ?|?(OS&, int); // with newline209 // OS& ?|?(OS&, int); // no newline, always chosen due to more specialization210 // }211 212 // mark type variable and specialization cost of forall clause213 convCost.incVar( function->forall.size() );214 convCost.decSpec( function->assertions.size() );215 216 return convCost;217 }218 219 void makeUnifiableVars(220 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,221 ast::AssertionSet & need222 ) {223 for ( auto & tyvar : type->forall ) {224 unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };225 }226 for ( auto & assn : type->assertions ) {227 need[ assn ].isUsed = true;228 }229 }230 231 /// Gets a default value from an initializer, nullptr if not present232 const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {233 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {234 if ( auto ce = si->value.as< ast::CastExpr >() ) {235 return ce->arg.as< ast::ConstantExpr >();236 } else {237 return si->value.as< ast::ConstantExpr >();238 }239 }240 return nullptr;241 }242 243 /// State to iteratively build a match of parameter expressions to arguments244 struct ArgPack {245 std::size_t parent; ///< Index of parent pack246 ast::ptr< ast::Expr > expr; ///< The argument stored here247 Cost cost; ///< The cost of this argument248 ast::TypeEnvironment env; ///< Environment for this pack249 ast::AssertionSet need; ///< Assertions outstanding for this pack250 ast::AssertionSet have; ///< Assertions found for this pack251 ast::OpenVarSet open; ///< Open variables for this pack252 unsigned nextArg; ///< Index of next argument in arguments list253 unsigned tupleStart; ///< Number of tuples that start at this index254 unsigned nextExpl; ///< Index of next exploded element255 unsigned explAlt; ///< Index of alternative for nextExpl > 0256 257 ArgPack()258 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),259 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}260 261 ArgPack(262 const ast::TypeEnvironment & env, const ast::AssertionSet & need,263 const ast::AssertionSet & have, const ast::OpenVarSet & open )264 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),265 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}266 267 ArgPack(268 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,269 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,270 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,271 unsigned nextExpl = 0, unsigned explAlt = 0 )272 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),273 have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),274 nextExpl( nextExpl ), explAlt( explAlt ) {}275 276 ArgPack(277 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,278 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )279 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),280 need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),281 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}282 283 /// true if this pack is in the middle of an exploded argument284 bool hasExpl() const { return nextExpl > 0; }285 286 /// Gets the list of exploded candidates for this pack287 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {288 return args[ nextArg-1 ][ explAlt ];289 }290 291 /// Ends a tuple expression, consolidating the appropriate args292 void endTuple( const std::vector< ArgPack > & packs ) {293 // add all expressions in tuple to list, summing cost294 std::deque< const ast::Expr * > exprs;295 const ArgPack * pack = this;296 if ( expr ) { exprs.emplace_front( expr ); }297 while ( pack->tupleStart == 0 ) {298 pack = &packs[pack->parent];299 exprs.emplace_front( pack->expr );300 cost += pack->cost;301 }302 // reset pack to appropriate tuple303 std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );304 expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };305 tupleStart = pack->tupleStart - 1;306 parent = pack->parent;307 }308 };309 310 /// Instantiates an argument to match a parameter, returns false if no matching results left311 bool instantiateArgument(312 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,313 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,314 unsigned nTuples = 0315 ) {316 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {317 // paramType is a TupleType -- group args into a TupleExpr318 ++nTuples;319 for ( const ast::Type * type : *tupleType ) {320 // xxx - dropping initializer changes behaviour from previous, but seems correct321 // ^^^ need to handle the case where a tuple has a default argument322 if ( ! instantiateArgument(323 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;324 nTuples = 0;325 }326 // re-constitute tuples for final generation327 for ( auto i = genStart; i < results.size(); ++i ) {328 results[i].endTuple( results );329 }330 return true;331 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {332 // paramType is a ttype, consumes all remaining arguments333 334 // completed tuples; will be spliced to end of results to finish335 std::vector< ArgPack > finalResults{};336 337 // iterate until all results completed338 std::size_t genEnd;339 ++nTuples;340 do {341 genEnd = results.size();342 343 // add another argument to results344 for ( std::size_t i = genStart; i < genEnd; ++i ) {345 unsigned nextArg = results[i].nextArg;346 347 // use next element of exploded tuple if present348 if ( results[i].hasExpl() ) {349 const ExplodedArg & expl = results[i].getExpl( args );350 351 unsigned nextExpl = results[i].nextExpl + 1;352 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }353 354 results.emplace_back(355 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),356 copy( results[i].need ), copy( results[i].have ),357 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,358 results[i].explAlt );359 360 continue;361 }362 363 // finish result when out of arguments364 if ( nextArg >= args.size() ) {365 ArgPack newResult{366 results[i].env, results[i].need, results[i].have, results[i].open };367 newResult.nextArg = nextArg;368 const ast::Type * argType = nullptr;369 370 if ( nTuples > 0 || ! results[i].expr ) {371 // first iteration or no expression to clone,372 // push empty tuple expression373 newResult.parent = i;374 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };375 argType = newResult.expr->result;376 } else {377 // clone result to collect tuple378 newResult.parent = results[i].parent;379 newResult.cost = results[i].cost;380 newResult.tupleStart = results[i].tupleStart;381 newResult.expr = results[i].expr;382 argType = newResult.expr->result;383 384 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {385 // the case where a ttype value is passed directly is special,386 // e.g. for argument forwarding purposes387 // xxx - what if passing multiple arguments, last of which is388 // ttype?389 // xxx - what would happen if unify was changed so that unifying390 // tuple391 // types flattened both before unifying lists? then pass in392 // TupleType (ttype) below.393 --newResult.tupleStart;394 } else {395 // collapse leftover arguments into tuple396 newResult.endTuple( results );397 argType = newResult.expr->result;398 }399 }400 401 // check unification for ttype before adding to final402 if (403 unify(404 ttype, argType, newResult.env, newResult.need, newResult.have,405 newResult.open, symtab )406 ) {407 finalResults.emplace_back( std::move( newResult ) );408 }409 410 continue;411 }412 413 // add each possible next argument414 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {415 const ExplodedArg & expl = args[nextArg][j];416 417 // fresh copies of parent parameters for this iteration418 ast::TypeEnvironment env = results[i].env;419 ast::OpenVarSet open = results[i].open;420 421 env.addActual( expl.env, open );422 423 // skip empty tuple arguments by (nearly) cloning parent into next gen424 if ( expl.exprs.empty() ) {425 results.emplace_back(426 results[i], std::move( env ), copy( results[i].need ),427 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );428 429 continue;430 }431 432 // add new result433 results.emplace_back(434 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),435 copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,436 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );437 }438 }439 440 // reset for next round441 genStart = genEnd;442 nTuples = 0;443 } while ( genEnd != results.size() );444 445 // splice final results onto results446 for ( std::size_t i = 0; i < finalResults.size(); ++i ) {447 results.emplace_back( std::move( finalResults[i] ) );448 }449 return ! finalResults.empty();450 }451 452 // iterate each current subresult453 std::size_t genEnd = results.size();454 for ( std::size_t i = genStart; i < genEnd; ++i ) {455 unsigned nextArg = results[i].nextArg;456 457 // use remainder of exploded tuple if present458 if ( results[i].hasExpl() ) {459 const ExplodedArg & expl = results[i].getExpl( args );460 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];461 462 ast::TypeEnvironment env = results[i].env;463 ast::AssertionSet need = results[i].need, have = results[i].have;464 ast::OpenVarSet open = results[i].open;465 466 const ast::Type * argType = expr->result;467 468 PRINT(469 std::cerr << "param type is ";470 ast::print( std::cerr, paramType );471 std::cerr << std::endl << "arg type is ";472 ast::print( std::cerr, argType );473 std::cerr << std::endl;474 )475 476 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {477 unsigned nextExpl = results[i].nextExpl + 1;478 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }479 480 results.emplace_back(481 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,482 nTuples, Cost::zero, nextExpl, results[i].explAlt );483 }484 485 continue;486 }487 488 // use default initializers if out of arguments489 if ( nextArg >= args.size() ) {490 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {491 ast::TypeEnvironment env = results[i].env;492 ast::AssertionSet need = results[i].need, have = results[i].have;493 ast::OpenVarSet open = results[i].open;494 495 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {496 results.emplace_back(497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),498 std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );499 }500 }501 502 continue;503 }504 505 // Check each possible next argument506 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {507 const ExplodedArg & expl = args[nextArg][j];508 509 // fresh copies of parent parameters for this iteration510 ast::TypeEnvironment env = results[i].env;511 ast::AssertionSet need = results[i].need, have = results[i].have;512 ast::OpenVarSet open = results[i].open;513 514 env.addActual( expl.env, open );515 516 // skip empty tuple arguments by (nearly) cloning parent into next gen517 if ( expl.exprs.empty() ) {518 results.emplace_back(519 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),520 nextArg + 1, expl.cost );521 522 continue;523 }524 525 // consider only first exploded arg526 const ast::Expr * expr = expl.exprs.front();527 const ast::Type * argType = expr->result;528 529 PRINT(530 std::cerr << "param type is ";531 ast::print( std::cerr, paramType );532 std::cerr << std::endl << "arg type is ";533 ast::print( std::cerr, argType );534 std::cerr << std::endl;535 )536 537 // attempt to unify types538 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {539 // add new result540 results.emplace_back(541 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),542 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );543 }544 }545 }546 547 // reset for next parameter548 genStart = genEnd;549 550 return genEnd != results.size(); // were any new results added?551 }552 553 /// Generate a cast expression from `arg` to `toType`554 const ast::Expr * restructureCast(555 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast556 ) {557 if (558 arg->result->size() > 1559 && ! toType->isVoid()560 && ! dynamic_cast< const ast::ReferenceType * >( toType )561 ) {562 // Argument is a tuple and the target type is neither void nor a reference. Cast each563 // member of the tuple to its corresponding target type, producing the tuple of those564 // cast expressions. If there are more components of the tuple than components in the565 // target type, then excess components do not come out in the result expression (but566 // UniqueExpr ensures that the side effects will still be produced)567 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {568 // expressions which may contain side effects require a single unique instance of569 // the expression570 arg = new ast::UniqueExpr{ arg->location, arg };571 }572 std::vector< ast::ptr< ast::Expr > > components;573 for ( unsigned i = 0; i < toType->size(); ++i ) {574 // cast each component575 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };576 components.emplace_back(577 restructureCast( idx, toType->getComponent( i ), isGenerated ) );578 }579 return new ast::TupleExpr{ arg->location, std::move( components ) };580 } else {581 // handle normally582 return new ast::CastExpr{ arg->location, arg, toType, isGenerated };583 }584 }585 586 /// Gets the name from an untyped member expression (must be NameExpr)587 const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {588 if ( memberExpr->member.as< ast::ConstantExpr >() ) {589 SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );590 }591 592 return memberExpr->member.strict_as< ast::NameExpr >()->name;593 }594 595 /// Actually visits expressions to find their candidate interpretations596 class Finder final : public ast::WithShortCircuiting {597 const ResolveContext & context;598 const ast::SymbolTable & symtab;599 public:600 // static size_t traceId;601 CandidateFinder & selfFinder;602 CandidateList & candidates;603 const ast::TypeEnvironment & tenv;604 ast::ptr< ast::Type > & targetType;605 606 enum Errors {607 NotFound,608 NoMatch,609 ArgsToFew,610 ArgsToMany,611 RetsToFew,612 RetsToMany,613 NoReason614 };615 616 struct {617 Errors code = NotFound;618 } reason;619 620 Finder( CandidateFinder & f )621 : context( f.context ), symtab( context.symtab ), selfFinder( f ),622 candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}623 624 void previsit( const ast::Node * ) { visit_children = false; }625 626 /// Convenience to add candidate to list627 template<typename... Args>628 void addCandidate( Args &&... args ) {629 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );630 reason.code = NoReason;631 }632 633 void postvisit( const ast::ApplicationExpr * applicationExpr ) {634 addCandidate( applicationExpr, tenv );635 }636 637 /// Set up candidate assertions for inference638 void inferParameters( CandidateRef & newCand, CandidateList & out ) {639 // Set need bindings for any unbound assertions640 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions641 for ( auto & assn : newCand->need ) {642 // skip already-matched assertions643 if ( assn.second.resnSlot != 0 ) continue;644 // assign slot for expression if needed645 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }646 // fix slot to assertion647 assn.second.resnSlot = crntResnSlot;648 }649 // pair slot to expression650 if ( crntResnSlot != 0 ) {651 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );652 }653 654 // add to output list; assertion satisfaction will occur later655 out.emplace_back( newCand );656 }657 658 /// Completes a function candidate with arguments located659 void validateFunctionCandidate(660 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,661 CandidateList & out662 ) {663 ast::ApplicationExpr * appExpr =664 new ast::ApplicationExpr{ func->expr->location, func->expr };665 // sum cost and accumulate arguments666 std::deque< const ast::Expr * > args;667 Cost cost = func->cost;668 const ArgPack * pack = &result;669 while ( pack->expr ) {670 args.emplace_front( pack->expr );671 cost += pack->cost;672 pack = &results[pack->parent];673 }674 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );675 appExpr->args = std::move( vargs );676 // build and validate new candidate677 auto newCand =678 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );679 PRINT(680 std::cerr << "instantiate function success: " << appExpr << std::endl;681 std::cerr << "need assertions:" << std::endl;682 ast::print( std::cerr, result.need, 2 );683 )684 inferParameters( newCand, out );685 }686 687 /// Builds a list of candidates for a function, storing them in out688 void makeFunctionCandidates(689 const CandidateRef & func, const ast::FunctionType * funcType,690 const ExplodedArgs_new & args, CandidateList & out691 ) {692 ast::OpenVarSet funcOpen;693 ast::AssertionSet funcNeed, funcHave;694 ast::TypeEnvironment funcEnv{ func->env };695 makeUnifiableVars( funcType, funcOpen, funcNeed );696 // add all type variables as open variables now so that those not used in the697 // parameter list are still considered open698 funcEnv.add( funcType->forall );699 700 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {701 // attempt to narrow based on expected target type702 const ast::Type * returnType = funcType->returns.front();703 if ( selfFinder.strictMode ) {704 if ( ! unifyExact(705 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden(), symtab ) // xxx - is no widening correct?706 ) {707 // unification failed, do not pursue this candidate708 return;709 }710 }711 else {712 if ( ! unify(713 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )714 ) {715 // unification failed, do not pursue this candidate716 return;717 }718 }719 }720 721 // iteratively build matches, one parameter at a time722 std::vector< ArgPack > results;723 results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );724 std::size_t genStart = 0;725 726 // xxx - how to handle default arg after change to ftype representation?727 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {728 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {729 // function may have default args only if directly calling by name730 // must use types on candidate however, due to RenameVars substitution731 auto nParams = funcType->params.size();732 733 for (size_t i=0; i<nParams; ++i) {734 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();735 if (!instantiateArgument(736 funcType->params[i], obj->init, args, results, genStart, symtab)) return;737 }738 goto endMatch;739 }740 }741 for ( const auto & param : funcType->params ) {742 // Try adding the arguments corresponding to the current parameter to the existing743 // matches744 // no default args for indirect calls745 if ( ! instantiateArgument(746 param, nullptr, args, results, genStart, symtab ) ) return;747 }748 749 endMatch:750 if ( funcType->isVarArgs ) {751 // append any unused arguments to vararg pack752 std::size_t genEnd;753 do {754 genEnd = results.size();755 756 // iterate results757 for ( std::size_t i = genStart; i < genEnd; ++i ) {758 unsigned nextArg = results[i].nextArg;759 760 // use remainder of exploded tuple if present761 if ( results[i].hasExpl() ) {762 const ExplodedArg & expl = results[i].getExpl( args );763 764 unsigned nextExpl = results[i].nextExpl + 1;765 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }766 767 results.emplace_back(768 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),769 copy( results[i].need ), copy( results[i].have ),770 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,771 results[i].explAlt );772 773 continue;774 }775 776 // finish result when out of arguments777 if ( nextArg >= args.size() ) {778 validateFunctionCandidate( func, results[i], results, out );779 780 continue;781 }782 783 // add each possible next argument784 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {785 const ExplodedArg & expl = args[nextArg][j];786 787 // fresh copies of parent parameters for this iteration788 ast::TypeEnvironment env = results[i].env;789 ast::OpenVarSet open = results[i].open;790 791 env.addActual( expl.env, open );792 793 // skip empty tuple arguments by (nearly) cloning parent into next gen794 if ( expl.exprs.empty() ) {795 results.emplace_back(796 results[i], std::move( env ), copy( results[i].need ),797 copy( results[i].have ), std::move( open ), nextArg + 1,798 expl.cost );799 800 continue;801 }802 803 // add new result804 results.emplace_back(805 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),806 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,807 expl.exprs.size() == 1 ? 0 : 1, j );808 }809 }810 811 genStart = genEnd;812 } while( genEnd != results.size() );813 } else {814 // filter out the results that don't use all the arguments815 for ( std::size_t i = genStart; i < results.size(); ++i ) {816 ArgPack & result = results[i];817 if ( ! result.hasExpl() && result.nextArg >= args.size() ) {818 validateFunctionCandidate( func, result, results, out );819 }820 }821 }822 }823 824 /// Adds implicit struct-conversions to the alternative list825 void addAnonConversions( const CandidateRef & cand ) {826 // adds anonymous member interpretations whenever an aggregate value type is seen.827 // it's okay for the aggregate expression to have reference type -- cast it to the828 // base type to treat the aggregate as the referenced value829 ast::ptr< ast::Expr > aggrExpr( cand->expr );830 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;831 cand->env.apply( aggrType );832 833 if ( aggrType.as< ast::ReferenceType >() ) {834 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };835 }836 837 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {838 addAggMembers( structInst, aggrExpr, *cand, Cost::unsafe, "" );839 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {840 addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );841 }842 }843 844 /// Adds aggregate member interpretations845 void addAggMembers(846 const ast::BaseInstType * aggrInst, const ast::Expr * expr,847 const Candidate & cand, const Cost & addedCost, const std::string & name848 ) {849 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {850 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );851 CandidateRef newCand = std::make_shared<Candidate>(852 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );853 // add anonymous member interpretations whenever an aggregate value type is seen854 // as a member expression855 addAnonConversions( newCand );856 candidates.emplace_back( std::move( newCand ) );857 }858 }859 860 /// Adds tuple member interpretations861 void addTupleMembers(862 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,863 const Cost & addedCost, const ast::Expr * member864 ) {865 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {866 // get the value of the constant expression as an int, must be between 0 and the867 // length of the tuple to have meaning868 long long val = constantExpr->intValue();869 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {870 addCandidate(871 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },872 addedCost );873 }874 }875 }876 877 void postvisit( const ast::UntypedExpr * untypedExpr ) {878 std::vector< CandidateFinder > argCandidates =879 selfFinder.findSubExprs( untypedExpr->args );880 881 // take care of possible tuple assignments882 // if not tuple assignment, handled as normal function call883 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );884 885 CandidateFinder funcFinder( context, tenv );886 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {887 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);888 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {889 assertf(!argCandidates.empty(), "special function call without argument");890 for (auto & firstArgCand: argCandidates[0]) {891 ast::ptr<ast::Type> argType = firstArgCand->expr->result;892 firstArgCand->env.apply(argType);893 // strip references894 // xxx - is this correct?895 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;896 897 // convert 1-tuple to plain type898 if (auto tuple = argType.as<ast::TupleType>()) {899 if (tuple->size() == 1) {900 argType = tuple->types[0];901 }902 }903 904 // if argType is an unbound type parameter, all special functions need to be searched.905 if (isUnboundType(argType)) {906 funcFinder.otypeKeys.clear();907 break;908 }909 910 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);911 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {912 // const ast::EnumDecl * enumDecl = enumInst->base; // Here913 // if ( const ast::Type* enumType = enumDecl->base ) {914 // // instance of enum (T) is a instance of type (T)915 // funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));916 // } else {917 // // instance of an untyped enum is techically int918 // funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));919 // }920 // }921 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));922 }923 }924 }925 // if candidates are already produced, do not fail926 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?927 // this means there exists ctor/assign functions with a tuple as first parameter.928 ResolvMode mode = {929 true, // adjust930 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name931 selfFinder.candidates.empty() // failfast if other options are not found932 };933 funcFinder.find( untypedExpr->func, mode );934 // short-circuit if no candidates935 // if ( funcFinder.candidates.empty() ) return;936 937 reason.code = NoMatch;938 939 // find function operators940 ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}941 CandidateFinder opFinder( context, tenv );942 // okay if there aren't any function operations943 opFinder.find( opExpr, ResolvMode::withoutFailFast() );944 PRINT(945 std::cerr << "known function ops:" << std::endl;946 print( std::cerr, opFinder.candidates, 1 );947 )948 949 // pre-explode arguments950 ExplodedArgs_new argExpansions;951 for ( const CandidateFinder & args : argCandidates ) {952 argExpansions.emplace_back();953 auto & argE = argExpansions.back();954 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }955 }956 957 // Find function matches958 CandidateList found;959 SemanticErrorException errors;960 for ( CandidateRef & func : funcFinder ) {961 try {962 PRINT(963 std::cerr << "working on alternative:" << std::endl;964 print( std::cerr, *func, 2 );965 )966 967 // check if the type is a pointer to function968 const ast::Type * funcResult = func->expr->result->stripReferences();969 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {970 if ( auto function = pointer->base.as< ast::FunctionType >() ) {971 // if (!selfFinder.allowVoid && function->returns.empty()) continue;972 CandidateRef newFunc{ new Candidate{ *func } };973 newFunc->expr =974 referenceToRvalueConversion( newFunc->expr, newFunc->cost );975 makeFunctionCandidates( newFunc, function, argExpansions, found );976 }977 } else if (978 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )979 ) {980 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {981 if ( auto function = clz->bound.as< ast::FunctionType >() ) {982 CandidateRef newFunc{ new Candidate{ *func } };983 newFunc->expr =984 referenceToRvalueConversion( newFunc->expr, newFunc->cost );985 makeFunctionCandidates( newFunc, function, argExpansions, found );986 }987 }988 }989 } catch ( SemanticErrorException & e ) { errors.append( e ); }990 }991 992 // Find matches on function operators `?()`993 if ( ! opFinder.candidates.empty() ) {994 // add exploded function alternatives to front of argument list995 std::vector< ExplodedArg > funcE;996 funcE.reserve( funcFinder.candidates.size() );997 for ( const CandidateRef & func : funcFinder ) {998 funcE.emplace_back( *func, symtab );999 }1000 argExpansions.emplace_front( std::move( funcE ) );1001 1002 for ( const CandidateRef & op : opFinder ) {1003 try {1004 // check if type is pointer-to-function1005 const ast::Type * opResult = op->expr->result->stripReferences();1006 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {1007 if ( auto function = pointer->base.as< ast::FunctionType >() ) {1008 CandidateRef newOp{ new Candidate{ *op} };1009 newOp->expr =1010 referenceToRvalueConversion( newOp->expr, newOp->cost );1011 makeFunctionCandidates( newOp, function, argExpansions, found );1012 }1013 }1014 } catch ( SemanticErrorException & e ) { errors.append( e ); }1015 }1016 }1017 1018 // Implement SFINAE; resolution errors are only errors if there aren't any non-error1019 // candidates1020 if ( found.empty() && ! errors.isEmpty() ) { throw errors; }1021 1022 // only keep the best matching intrinsic result to match C semantics (no unexpected narrowing/widening)1023 // TODO: keep one for each set of argument candidates?1024 Cost intrinsicCost = Cost::infinity;1025 CandidateList intrinsicResult;1026 1027 // Compute conversion costs1028 for ( CandidateRef & withFunc : found ) {1029 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );1030 1031 PRINT(1032 auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();1033 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();1034 auto function = pointer->base.strict_as< ast::FunctionType >();1035 1036 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;1037 std::cerr << "parameters are:" << std::endl;1038 ast::printAll( std::cerr, function->params, 2 );1039 std::cerr << "arguments are:" << std::endl;1040 ast::printAll( std::cerr, appExpr->args, 2 );1041 std::cerr << "bindings are:" << std::endl;1042 ast::print( std::cerr, withFunc->env, 2 );1043 std::cerr << "cost is: " << withFunc->cost << std::endl;1044 std::cerr << "cost of conversion is:" << cvtCost << std::endl;1045 )1046 1047 if ( cvtCost != Cost::infinity ) {1048 withFunc->cvtCost = cvtCost;1049 withFunc->cost += cvtCost;1050 auto func = withFunc->expr.strict_as<ast::ApplicationExpr>()->func.as<ast::VariableExpr>();1051 if (func && func->var->linkage == ast::Linkage::Intrinsic) {1052 if (withFunc->cost < intrinsicCost) {1053 intrinsicResult.clear();1054 intrinsicCost = withFunc->cost;1055 }1056 if (withFunc->cost == intrinsicCost) {1057 intrinsicResult.emplace_back(std::move(withFunc));1058 }1059 }1060 else {1061 candidates.emplace_back( std::move( withFunc ) );1062 }1063 }1064 }1065 spliceBegin( candidates, intrinsicResult );1066 found = std::move( candidates );1067 1068 // use a new list so that candidates are not examined by addAnonConversions twice1069 // CandidateList winners = findMinCost( found );1070 // promoteCvtCost( winners );1071 1072 // function may return a struct/union value, in which case we need to add candidates1073 // for implicit conversions to each of the anonymous members, which must happen after1074 // `findMinCost`, since anon conversions are never the cheapest1075 for ( const CandidateRef & c : found ) {1076 addAnonConversions( c );1077 }1078 // would this be too slow when we don't check cost anymore?1079 spliceBegin( candidates, found );1080 1081 if ( candidates.empty() && targetType && ! targetType->isVoid() && !selfFinder.strictMode ) {1082 // If resolution is unsuccessful with a target type, try again without, since it1083 // will sometimes succeed when it wouldn't with a target type binding.1084 // For example:1085 // forall( otype T ) T & ?[]( T *, ptrdiff_t );1086 // const char * x = "hello world";1087 // unsigned char ch = x[0];1088 // Fails with simple return type binding (xxx -- check this!) as follows:1089 // * T is bound to unsigned char1090 // * (x: const char *) is unified with unsigned char *, which fails1091 // xxx -- fix this better1092 targetType = nullptr;1093 postvisit( untypedExpr );1094 }1095 }1096 1097 /// true if expression is an lvalue1098 static bool isLvalue( const ast::Expr * x ) {1099 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );1100 }1101 1102 void postvisit( const ast::AddressExpr * addressExpr ) {1103 CandidateFinder finder( context, tenv );1104 finder.find( addressExpr->arg );1105 1106 if( finder.candidates.empty() ) return;1107 1108 reason.code = NoMatch;1109 1110 for ( CandidateRef & r : finder.candidates ) {1111 if ( ! isLvalue( r->expr ) ) continue;1112 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );1113 }1114 }1115 1116 void postvisit( const ast::LabelAddressExpr * labelExpr ) {1117 addCandidate( labelExpr, tenv );1118 }1119 1120 void postvisit( const ast::CastExpr * castExpr ) {1121 ast::ptr< ast::Type > toType = castExpr->result;1122 assert( toType );1123 toType = resolveTypeof( toType, context );1124 toType = adjustExprType( toType, tenv, symtab );1125 1126 CandidateFinder finder( context, tenv, toType );1127 if (toType->isVoid()) {1128 finder.allowVoid = true;1129 }1130 if ( castExpr->kind == ast::CastExpr::Return ) {1131 finder.strictMode = true;1132 finder.find( castExpr->arg, ResolvMode::withAdjustment() );1133 1134 // return casts are eliminated (merely selecting an overload, no actual operation)1135 candidates = std::move(finder.candidates);1136 }1137 finder.find( castExpr->arg, ResolvMode::withAdjustment() );1138 1139 if( !finder.candidates.empty() ) reason.code = NoMatch;1140 1141 CandidateList matches;1142 Cost minExprCost = Cost::infinity;1143 Cost minCastCost = Cost::infinity;1144 for ( CandidateRef & cand : finder.candidates ) {1145 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;1146 ast::OpenVarSet open( cand->open );1147 1148 cand->env.extractOpenVars( open );1149 1150 // It is possible that a cast can throw away some values in a multiply-valued1151 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the1152 // subexpression results that are cast directly. The candidate is invalid if it1153 // has fewer results than there are types to cast to.1154 int discardedValues = cand->expr->result->size() - toType->size();1155 if ( discardedValues < 0 ) continue;1156 1157 // unification run for side-effects1158 unify( toType, cand->expr->result, cand->env, need, have, open, symtab );1159 Cost thisCost =1160 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)1161 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )1162 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );1163 1164 PRINT(1165 std::cerr << "working on cast with result: " << toType << std::endl;1166 std::cerr << "and expr type: " << cand->expr->result << std::endl;1167 std::cerr << "env: " << cand->env << std::endl;1168 )1169 if ( thisCost != Cost::infinity ) {1170 PRINT(1171 std::cerr << "has finite cost." << std::endl;1172 )1173 // count one safe conversion for each value that is thrown away1174 thisCost.incSafe( discardedValues );1175 // select first on argument cost, then conversion cost1176 if (cand->cost < minExprCost || cand->cost == minExprCost && thisCost < minCastCost) {1177 minExprCost = cand->cost;1178 minCastCost = thisCost;1179 matches.clear();1180 1181 1182 }1183 // ambiguous case, still output candidates to print in error message1184 if (cand->cost == minExprCost && thisCost == minCastCost) {1185 CandidateRef newCand = std::make_shared<Candidate>(1186 restructureCast( cand->expr, toType, castExpr->isGenerated ),1187 copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost);1188 // currently assertions are always resolved immediately so this should have no effect.1189 // if this somehow changes in the future (e.g. delayed by indeterminate return type)1190 // we may need to revisit the logic.1191 inferParameters( newCand, matches );1192 }1193 // else skip, better alternatives found1194 1195 }1196 }1197 candidates = std::move(matches);1198 1199 //CandidateList minArgCost = findMinCost( matches );1200 //promoteCvtCost( minArgCost );1201 //candidates = findMinCost( minArgCost );1202 }1203 1204 void postvisit( const ast::VirtualCastExpr * castExpr ) {1205 assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );1206 CandidateFinder finder( context, tenv );1207 // don't prune here, all alternatives guaranteed to have same type1208 finder.find( castExpr->arg, ResolvMode::withoutPrune() );1209 for ( CandidateRef & r : finder.candidates ) {1210 addCandidate(1211 *r,1212 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );1213 }1214 }1215 1216 void postvisit( const ast::KeywordCastExpr * castExpr ) {1217 const auto & loc = castExpr->location;1218 assertf( castExpr->result, "Cast target should have been set in Validate." );1219 auto ref = castExpr->result.strict_as<ast::ReferenceType>();1220 auto inst = ref->base.strict_as<ast::StructInstType>();1221 auto target = inst->base.get();1222 1223 CandidateFinder finder( context, tenv );1224 1225 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {1226 for(auto & cand : found) {1227 const ast::Type * expr = cand->expr->result.get();1228 if(expect_ref) {1229 auto res = dynamic_cast<const ast::ReferenceType*>(expr);1230 if(!res) { continue; }1231 expr = res->base.get();1232 }1233 1234 if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {1235 auto td = cand->env.lookup(*insttype);1236 if(!td) { continue; }1237 expr = td->bound.get();1238 }1239 1240 if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {1241 if(base->base == target) {1242 candidates.push_back( std::move(cand) );1243 reason.code = NoReason;1244 }1245 }1246 }1247 };1248 1249 try {1250 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd1251 // Clone is purely for memory management1252 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };1253 1254 // don't prune here, since it's guaranteed all alternatives will have the same type1255 finder.find( tech1.get(), ResolvMode::withoutPrune() );1256 pick_alternatives(finder.candidates, false);1257 1258 return;1259 } catch(SemanticErrorException & ) {}1260 1261 // Fallback : turn (thread&)X into (thread$&)get_thread(X)1262 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };1263 // don't prune here, since it's guaranteed all alternatives will have the same type1264 finder.find( fallback.get(), ResolvMode::withoutPrune() );1265 1266 pick_alternatives(finder.candidates, true);1267 1268 // Whatever happens here, we have no more fallbacks1269 }1270 1271 void postvisit( const ast::UntypedMemberExpr * memberExpr ) {1272 CandidateFinder aggFinder( context, tenv );1273 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );1274 for ( CandidateRef & agg : aggFinder.candidates ) {1275 // it's okay for the aggregate expression to have reference type -- cast it to the1276 // base type to treat the aggregate as the referenced value1277 Cost addedCost = Cost::zero;1278 agg->expr = referenceToRvalueConversion( agg->expr, addedCost );1279 1280 // find member of the given type1281 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {1282 addAggMembers(1283 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );1284 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {1285 addAggMembers(1286 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );1287 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {1288 addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );1289 }1290 }1291 }1292 1293 void postvisit( const ast::MemberExpr * memberExpr ) {1294 addCandidate( memberExpr, tenv );1295 }1296 1297 void postvisit( const ast::NameExpr * nameExpr ) {1298 std::vector< ast::SymbolTable::IdData > declList;1299 if (!selfFinder.otypeKeys.empty()) {1300 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);1301 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());1302 1303 for (auto & otypeKey: selfFinder.otypeKeys) {1304 auto result = symtab.specialLookupId(kind, otypeKey);1305 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));1306 }1307 }1308 else {1309 declList = symtab.lookupId( nameExpr->name );1310 }1311 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )1312 1313 if( declList.empty() ) return;1314 1315 reason.code = NoMatch;1316 1317 for ( auto & data : declList ) {1318 Cost cost = Cost::zero;1319 ast::Expr * newExpr = data.combine( nameExpr->location, cost );1320 1321 CandidateRef newCand = std::make_shared<Candidate>(1322 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, cost );1323 1324 if (newCand->expr->env) {1325 newCand->env.add(*newCand->expr->env);1326 auto mutExpr = newCand->expr.get_and_mutate();1327 mutExpr->env = nullptr;1328 newCand->expr = mutExpr;1329 }1330 1331 PRINT(1332 std::cerr << "decl is ";1333 ast::print( std::cerr, data.id );1334 std::cerr << std::endl;1335 std::cerr << "newExpr is ";1336 ast::print( std::cerr, newExpr );1337 std::cerr << std::endl;1338 )1339 newCand->expr = ast::mutate_field(1340 newCand->expr.get(), &ast::Expr::result,1341 renameTyVars( newCand->expr->result ) );1342 // add anonymous member interpretations whenever an aggregate value type is seen1343 // as a name expression1344 addAnonConversions( newCand );1345 candidates.emplace_back( std::move( newCand ) );1346 }1347 }1348 1349 void postvisit( const ast::VariableExpr * variableExpr ) {1350 // not sufficient to just pass `variableExpr` here, type might have changed since1351 // creation1352 addCandidate(1353 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );1354 }1355 1356 void postvisit( const ast::ConstantExpr * constantExpr ) {1357 addCandidate( constantExpr, tenv );1358 }1359 1360 void postvisit( const ast::SizeofExpr * sizeofExpr ) {1361 if ( sizeofExpr->type ) {1362 addCandidate(1363 new ast::SizeofExpr{1364 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },1365 tenv );1366 } else {1367 // find all candidates for the argument to sizeof1368 CandidateFinder finder( context, tenv );1369 finder.find( sizeofExpr->expr );1370 // find the lowest-cost candidate, otherwise ambiguous1371 CandidateList winners = findMinCost( finder.candidates );1372 if ( winners.size() != 1 ) {1373 SemanticError(1374 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );1375 }1376 // return the lowest-cost candidate1377 CandidateRef & choice = winners.front();1378 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );1379 choice->cost = Cost::zero;1380 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );1381 }1382 }1383 1384 void postvisit( const ast::AlignofExpr * alignofExpr ) {1385 if ( alignofExpr->type ) {1386 addCandidate(1387 new ast::AlignofExpr{1388 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },1389 tenv );1390 } else {1391 // find all candidates for the argument to alignof1392 CandidateFinder finder( context, tenv );1393 finder.find( alignofExpr->expr );1394 // find the lowest-cost candidate, otherwise ambiguous1395 CandidateList winners = findMinCost( finder.candidates );1396 if ( winners.size() != 1 ) {1397 SemanticError(1398 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );1399 }1400 // return the lowest-cost candidate1401 CandidateRef & choice = winners.front();1402 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );1403 choice->cost = Cost::zero;1404 addCandidate(1405 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );1406 }1407 }1408 1409 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {1410 const ast::BaseInstType * aggInst;1411 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;1412 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;1413 else return;1414 1415 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {1416 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );1417 addCandidate(1418 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );1419 }1420 }1421 1422 void postvisit( const ast::OffsetofExpr * offsetofExpr ) {1423 addCandidate( offsetofExpr, tenv );1424 }1425 1426 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {1427 addCandidate( offsetPackExpr, tenv );1428 }1429 1430 void postvisit( const ast::LogicalExpr * logicalExpr ) {1431 CandidateFinder finder1( context, tenv );1432 finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );1433 if ( finder1.candidates.empty() ) return;1434 1435 CandidateFinder finder2( context, tenv );1436 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );1437 if ( finder2.candidates.empty() ) return;1438 1439 reason.code = NoMatch;1440 1441 for ( const CandidateRef & r1 : finder1.candidates ) {1442 for ( const CandidateRef & r2 : finder2.candidates ) {1443 ast::TypeEnvironment env{ r1->env };1444 env.simpleCombine( r2->env );1445 ast::OpenVarSet open{ r1->open };1446 mergeOpenVars( open, r2->open );1447 ast::AssertionSet need;1448 mergeAssertionSet( need, r1->need );1449 mergeAssertionSet( need, r2->need );1450 1451 addCandidate(1452 new ast::LogicalExpr{1453 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },1454 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );1455 }1456 }1457 }1458 1459 void postvisit( const ast::ConditionalExpr * conditionalExpr ) {1460 // candidates for condition1461 CandidateFinder finder1( context, tenv );1462 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );1463 if ( finder1.candidates.empty() ) return;1464 1465 // candidates for true result1466 CandidateFinder finder2( context, tenv );1467 finder2.allowVoid = true;1468 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );1469 if ( finder2.candidates.empty() ) return;1470 1471 // candidates for false result1472 CandidateFinder finder3( context, tenv );1473 finder3.allowVoid = true;1474 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );1475 if ( finder3.candidates.empty() ) return;1476 1477 reason.code = NoMatch;1478 1479 for ( const CandidateRef & r1 : finder1.candidates ) {1480 for ( const CandidateRef & r2 : finder2.candidates ) {1481 for ( const CandidateRef & r3 : finder3.candidates ) {1482 ast::TypeEnvironment env{ r1->env };1483 env.simpleCombine( r2->env );1484 env.simpleCombine( r3->env );1485 ast::OpenVarSet open{ r1->open };1486 mergeOpenVars( open, r2->open );1487 mergeOpenVars( open, r3->open );1488 ast::AssertionSet need;1489 mergeAssertionSet( need, r1->need );1490 mergeAssertionSet( need, r2->need );1491 mergeAssertionSet( need, r3->need );1492 ast::AssertionSet have;1493 1494 // unify true and false results, then infer parameters to produce new1495 // candidates1496 ast::ptr< ast::Type > common;1497 if (1498 unify(1499 r2->expr->result, r3->expr->result, env, need, have, open, symtab,1500 common )1501 ) {1502 // generate typed expression1503 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{1504 conditionalExpr->location, r1->expr, r2->expr, r3->expr };1505 newExpr->result = common ? common : r2->expr->result;1506 // convert both options to result type1507 Cost cost = r1->cost + r2->cost + r3->cost;1508 newExpr->arg2 = computeExpressionConversionCost(1509 newExpr->arg2, newExpr->result, symtab, env, cost );1510 newExpr->arg3 = computeExpressionConversionCost(1511 newExpr->arg3, newExpr->result, symtab, env, cost );1512 // output candidate1513 CandidateRef newCand = std::make_shared<Candidate>(1514 newExpr, std::move( env ), std::move( open ), std::move( need ), cost );1515 inferParameters( newCand, candidates );1516 }1517 }1518 }1519 }1520 }1521 1522 void postvisit( const ast::CommaExpr * commaExpr ) {1523 ast::TypeEnvironment env{ tenv };1524 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );1525 1526 CandidateFinder finder2( context, env );1527 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );1528 1529 for ( const CandidateRef & r2 : finder2.candidates ) {1530 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );1531 }1532 }1533 1534 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {1535 addCandidate( ctorExpr, tenv );1536 }1537 1538 void postvisit( const ast::ConstructorExpr * ctorExpr ) {1539 CandidateFinder finder( context, tenv );1540 finder.allowVoid = true;1541 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );1542 for ( CandidateRef & r : finder.candidates ) {1543 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );1544 }1545 }1546 1547 void postvisit( const ast::RangeExpr * rangeExpr ) {1548 // resolve low and high, accept candidates where low and high types unify1549 CandidateFinder finder1( context, tenv );1550 finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );1551 if ( finder1.candidates.empty() ) return;1552 1553 CandidateFinder finder2( context, tenv );1554 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );1555 if ( finder2.candidates.empty() ) return;1556 1557 reason.code = NoMatch;1558 1559 for ( const CandidateRef & r1 : finder1.candidates ) {1560 for ( const CandidateRef & r2 : finder2.candidates ) {1561 ast::TypeEnvironment env{ r1->env };1562 env.simpleCombine( r2->env );1563 ast::OpenVarSet open{ r1->open };1564 mergeOpenVars( open, r2->open );1565 ast::AssertionSet need;1566 mergeAssertionSet( need, r1->need );1567 mergeAssertionSet( need, r2->need );1568 ast::AssertionSet have;1569 1570 ast::ptr< ast::Type > common;1571 if (1572 unify(1573 r1->expr->result, r2->expr->result, env, need, have, open, symtab,1574 common )1575 ) {1576 // generate new expression1577 ast::RangeExpr * newExpr =1578 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };1579 newExpr->result = common ? common : r1->expr->result;1580 // add candidate1581 CandidateRef newCand = std::make_shared<Candidate>(1582 newExpr, std::move( env ), std::move( open ), std::move( need ),1583 r1->cost + r2->cost );1584 inferParameters( newCand, candidates );1585 }1586 }1587 }1588 }1589 1590 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {1591 std::vector< CandidateFinder > subCandidates =1592 selfFinder.findSubExprs( tupleExpr->exprs );1593 std::vector< CandidateList > possibilities;1594 combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );1595 1596 for ( const CandidateList & subs : possibilities ) {1597 std::vector< ast::ptr< ast::Expr > > exprs;1598 exprs.reserve( subs.size() );1599 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }1600 1601 ast::TypeEnvironment env;1602 ast::OpenVarSet open;1603 ast::AssertionSet need;1604 for ( const CandidateRef & sub : subs ) {1605 env.simpleCombine( sub->env );1606 mergeOpenVars( open, sub->open );1607 mergeAssertionSet( need, sub->need );1608 }1609 1610 addCandidate(1611 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },1612 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );1613 }1614 }1615 1616 void postvisit( const ast::TupleExpr * tupleExpr ) {1617 addCandidate( tupleExpr, tenv );1618 }1619 1620 void postvisit( const ast::TupleIndexExpr * tupleExpr ) {1621 addCandidate( tupleExpr, tenv );1622 }1623 1624 void postvisit( const ast::TupleAssignExpr * tupleExpr ) {1625 addCandidate( tupleExpr, tenv );1626 }1627 1628 void postvisit( const ast::UniqueExpr * unqExpr ) {1629 CandidateFinder finder( context, tenv );1630 finder.find( unqExpr->expr, ResolvMode::withAdjustment() );1631 for ( CandidateRef & r : finder.candidates ) {1632 // ensure that the the id is passed on so that the expressions are "linked"1633 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );1634 }1635 }1636 1637 void postvisit( const ast::StmtExpr * stmtExpr ) {1638 addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );1639 }1640 1641 void postvisit( const ast::UntypedInitExpr * initExpr ) {1642 // handle each option like a cast1643 CandidateList matches;1644 PRINT(1645 std::cerr << "untyped init expr: " << initExpr << std::endl;1646 )1647 // O(n^2) checks of d-types with e-types1648 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {1649 // calculate target type1650 const ast::Type * toType = resolveTypeof( initAlt.type, context );1651 toType = adjustExprType( toType, tenv, symtab );1652 // The call to find must occur inside this loop, otherwise polymorphic return1653 // types are not bound to the initialization type, since return type variables are1654 // only open for the duration of resolving the UntypedExpr.1655 CandidateFinder finder( context, tenv, toType );1656 finder.find( initExpr->expr, ResolvMode::withAdjustment() );1657 1658 Cost minExprCost = Cost::infinity;1659 Cost minCastCost = Cost::infinity;1660 for ( CandidateRef & cand : finder.candidates ) {1661 if(reason.code == NotFound) reason.code = NoMatch;1662 1663 ast::TypeEnvironment env{ cand->env };1664 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;1665 ast::OpenVarSet open{ cand->open };1666 1667 PRINT(1668 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl;1669 )1670 1671 // It is possible that a cast can throw away some values in a multiply-valued1672 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of1673 // the subexpression results that are cast directly. The candidate is invalid1674 // if it has fewer results than there are types to cast to.1675 int discardedValues = cand->expr->result->size() - toType->size();1676 if ( discardedValues < 0 ) continue;1677 1678 // unification run for side-effects1679 bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );1680 (void) canUnify;1681 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),1682 symtab, env );1683 PRINT(1684 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),1685 symtab, env );1686 std::cerr << "Considering initialization:";1687 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl;1688 std::cerr << std::endl << " TO: " << toType << std::endl;1689 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed");1690 std::cerr << std::endl << " Legacy cost " << legacyCost;1691 std::cerr << std::endl << " New cost " << thisCost;1692 std::cerr << std::endl;1693 )1694 if ( thisCost != Cost::infinity ) {1695 // count one safe conversion for each value that is thrown away1696 thisCost.incSafe( discardedValues );1697 if (cand->cost < minExprCost || cand->cost == minExprCost && thisCost < minCastCost) {1698 minExprCost = cand->cost;1699 minCastCost = thisCost;1700 matches.clear();1701 }1702 // ambiguous case, still output candidates to print in error message1703 if (cand->cost == minExprCost && thisCost == minCastCost) {1704 CandidateRef newCand = std::make_shared<Candidate>(1705 new ast::InitExpr{1706 initExpr->location, restructureCast( cand->expr, toType ),1707 initAlt.designation },1708 std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );1709 // currently assertions are always resolved immediately so this should have no effect.1710 // if this somehow changes in the future (e.g. delayed by indeterminate return type)1711 // we may need to revisit the logic.1712 inferParameters( newCand, matches );1713 }1714 1715 }1716 1717 }1718 1719 }1720 1721 // select first on argument cost, then conversion cost1722 // CandidateList minArgCost = findMinCost( matches );1723 // promoteCvtCost( minArgCost );1724 // candidates = findMinCost( minArgCost );1725 candidates = std::move(matches);1726 }1727 1728 void postvisit( const ast::InitExpr * ) {1729 assertf( false, "CandidateFinder should never see a resolved InitExpr." );1730 }1731 1732 void postvisit( const ast::DeletedExpr * ) {1733 assertf( false, "CandidateFinder should never see a DeletedExpr." );1734 }1735 1736 void postvisit( const ast::GenericExpr * ) {1737 assertf( false, "_Generic is not yet supported." );1738 }1739 };1740 1741 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");1742 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given1743 /// return type. Skips ambiguous candidates.1744 1745 } // anonymous namespace1746 1747 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {1748 struct PruneStruct {1749 CandidateRef candidate;1750 bool ambiguous;1751 1752 PruneStruct() = default;1753 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}1754 };1755 1756 // find lowest-cost candidate for each type1757 std::unordered_map< std::string, PruneStruct > selected;1758 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found1759 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});1760 for ( CandidateRef & candidate : candidates ) {1761 std::string mangleName;1762 {1763 ast::ptr< ast::Type > newType = candidate->expr->result;1764 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());1765 candidate->env.apply( newType );1766 mangleName = Mangle::mangle( newType );1767 }1768 1769 auto found = selected.find( mangleName );1770 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {1771 PRINT(1772 std::cerr << "cost " << candidate->cost << " loses to "1773 << found->second.candidate->cost << std::endl;1774 )1775 continue;1776 }1777 1778 // xxx - when do satisfyAssertions produce more than 1 result?1779 // this should only happen when initial result type contains1780 // unbound type parameters, then it should never be pruned by1781 // the previous step, since renameTyVars guarantees the mangled name1782 // is unique.1783 CandidateList satisfied;1784 bool needRecomputeKey = false;1785 if (candidate->need.empty()) {1786 satisfied.emplace_back(candidate);1787 }1788 else {1789 satisfyAssertions(candidate, context.symtab, satisfied, errors);1790 needRecomputeKey = true;1791 }1792 1793 for (auto & newCand : satisfied) {1794 // recomputes type key, if satisfyAssertions changed it1795 if (needRecomputeKey)1796 {1797 ast::ptr< ast::Type > newType = newCand->expr->result;1798 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());1799 newCand->env.apply( newType );1800 mangleName = Mangle::mangle( newType );1801 }1802 auto found = selected.find( mangleName );1803 if ( found != selected.end() ) {1804 // tiebreaking by picking the lower cost on CURRENT expression1805 // NOTE: this behavior is different from C semantics.1806 // Specific remediations are performed for C operators at postvisit(UntypedExpr).1807 // Further investigations may take place.1808 if ( newCand->cost < found->second.candidate->cost1809 || (newCand->cost == found->second.candidate->cost && newCand->cvtCost < found->second.candidate->cvtCost) ) {1810 PRINT(1811 std::cerr << "cost " << newCand->cost << " beats "1812 << found->second.candidate->cost << std::endl;1813 )1814 1815 found->second = PruneStruct{ newCand };1816 } else if ( newCand->cost == found->second.candidate->cost && newCand->cvtCost == found->second.candidate->cvtCost) {1817 // if one of the candidates contains a deleted identifier, can pick the other,1818 // since deleted expressions should not be ambiguous if there is another option1819 // that is at least as good1820 if ( findDeletedExpr( newCand->expr ) ) {1821 // do nothing1822 PRINT( std::cerr << "candidate is deleted" << std::endl; )1823 } else if ( findDeletedExpr( found->second.candidate->expr ) ) {1824 PRINT( std::cerr << "current is deleted" << std::endl; )1825 found->second = PruneStruct{ newCand };1826 } else {1827 PRINT( std::cerr << "marking ambiguous" << std::endl; )1828 found->second.ambiguous = true;1829 }1830 } else {1831 // xxx - can satisfyAssertions increase the cost?1832 PRINT(1833 std::cerr << "cost " << newCand->cost << " loses to "1834 << found->second.candidate->cost << std::endl;1835 )1836 }1837 } else {1838 selected.emplace_hint( found, mangleName, newCand );1839 }1840 }1841 }1842 1843 // report unambiguous min-cost candidates1844 // CandidateList out;1845 for ( auto & target : selected ) {1846 if ( target.second.ambiguous ) continue;1847 1848 CandidateRef cand = target.second.candidate;1849 1850 ast::ptr< ast::Type > newResult = cand->expr->result;1851 cand->env.applyFree( newResult );1852 cand->expr = ast::mutate_field(1853 cand->expr.get(), &ast::Expr::result, std::move( newResult ) );1854 1855 out.emplace_back( cand );1856 }1857 // if everything is lost in satisfyAssertions, report the error1858 return !selected.empty();1859 }1860 1861 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {1862 // Find alternatives for expression1863 ast::Pass<Finder> finder{ *this };1864 expr->accept( finder );1865 1866 if ( mode.failFast && candidates.empty() ) {1867 switch(finder.core.reason.code) {1868 case Finder::NotFound:1869 { SemanticError( expr, "No alternatives for expression " ); break; }1870 case Finder::NoMatch:1871 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }1872 case Finder::ArgsToFew:1873 case Finder::ArgsToMany:1874 case Finder::RetsToFew:1875 case Finder::RetsToMany:1876 case Finder::NoReason:1877 default:1878 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }1879 }1880 }1881 1882 /*1883 if ( mode.satisfyAssns || mode.prune ) {1884 // trim candidates to just those where the assertions are satisfiable1885 // - necessary pre-requisite to pruning1886 CandidateList satisfied;1887 std::vector< std::string > errors;1888 for ( CandidateRef & candidate : candidates ) {1889 satisfyAssertions( candidate, localSyms, satisfied, errors );1890 }1891 1892 // fail early if none such1893 if ( mode.failFast && satisfied.empty() ) {1894 std::ostringstream stream;1895 stream << "No alternatives with satisfiable assertions for " << expr << "\n";1896 for ( const auto& err : errors ) {1897 stream << err;1898 }1899 SemanticError( expr->location, stream.str() );1900 }1901 1902 // reset candidates1903 candidates = move( satisfied );1904 }1905 */1906 1907 // if ( mode.prune ) {1908 // optimization: don't prune for NameExpr since it never has cost1909 if ( mode.prune && !dynamic_cast<const ast::NameExpr *>(expr)) {1910 // trim candidates to single best one1911 PRINT(1912 std::cerr << "alternatives before prune:" << std::endl;1913 print( std::cerr, candidates );1914 )1915 1916 CandidateList pruned;1917 std::vector<std::string> errors;1918 bool found = pruneCandidates( candidates, pruned, errors );1919 1920 if ( mode.failFast && pruned.empty() ) {1921 std::ostringstream stream;1922 if (found) {1923 CandidateList winners = findMinCost( candidates );1924 stream << "Cannot choose between " << winners.size() << " alternatives for "1925 "expression\n";1926 ast::print( stream, expr );1927 stream << " Alternatives are:\n";1928 print( stream, winners, 1 );1929 SemanticError( expr->location, stream.str() );1930 }1931 else {1932 stream << "No alternatives with satisfiable assertions for " << expr << "\n";1933 for ( const auto& err : errors ) {1934 stream << err;1935 }1936 SemanticError( expr->location, stream.str() );1937 }1938 }1939 1940 auto oldsize = candidates.size();1941 candidates = std::move( pruned );1942 1943 PRINT(1944 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;1945 )1946 PRINT(1947 std::cerr << "there are " << candidates.size() << " alternatives after elimination"1948 << std::endl;1949 )1950 }1951 1952 // adjust types after pruning so that types substituted by pruneAlternatives are correctly1953 // adjusted1954 if ( mode.adjust ) {1955 for ( CandidateRef & r : candidates ) {1956 r->expr = ast::mutate_field(1957 r->expr.get(), &ast::Expr::result,1958 adjustExprType( r->expr->result, r->env, context.symtab ) );1959 }1960 }1961 1962 // Central location to handle gcc extension keyword, etc. for all expressions1963 for ( CandidateRef & r : candidates ) {1964 if ( r->expr->extension != expr->extension ) {1965 r->expr.get_and_mutate()->extension = expr->extension;1966 }1967 }1968 }1969 1970 std::vector< CandidateFinder > CandidateFinder::findSubExprs(1971 const std::vector< ast::ptr< ast::Expr > > & xs1972 ) {1973 std::vector< CandidateFinder > out;1974 1975 for ( const auto & x : xs ) {1976 out.emplace_back( context, env );1977 out.back().find( x, ResolvMode::withAdjustment() );1978 1979 PRINT(1980 std::cerr << "findSubExprs" << std::endl;1981 print( std::cerr, out.back().candidates );1982 )1983 }1984 1985 return out;1986 }1987 1988 1970 } // namespace ResolvExpr 1989 1971
Note:
See TracChangeset
for help on using the changeset viewer.