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