Changes in / [16e0dcb:f7f997a]
- Files:
-
- 22 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/AdjustExprType.cc
r16e0dcb rf7f997a 23 23 24 24 namespace { 25 class AdjustExprType final : public ast::WithShortCircuiting {26 const ast::SymbolTable & symtab;27 public:28 const ast::TypeEnvironment & tenv;29 25 30 AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 31 : symtab( syms ), tenv( e ) {} 26 class AdjustExprType final : public ast::WithShortCircuiting { 27 const ast::SymbolTable & symtab; 28 public: 29 const ast::TypeEnvironment & tenv; 32 30 33 void previsit( const ast::VoidType * ) { visit_children = false; } 34 void previsit( const ast::BasicType * ) { visit_children = false; } 35 void previsit( const ast::PointerType * ) { visit_children = false; } 36 void previsit( const ast::ArrayType * ) { visit_children = false; } 37 void previsit( const ast::FunctionType * ) { visit_children = false; } 38 void previsit( const ast::StructInstType * ) { visit_children = false; } 39 void previsit( const ast::UnionInstType * ) { visit_children = false; } 40 void previsit( const ast::EnumInstType * ) { visit_children = false; } 41 void previsit( const ast::TraitInstType * ) { visit_children = false; } 42 void previsit( const ast::TypeInstType * ) { visit_children = false; } 43 void previsit( const ast::TupleType * ) { visit_children = false; } 44 void previsit( const ast::VarArgsType * ) { visit_children = false; } 45 void previsit( const ast::ZeroType * ) { visit_children = false; } 46 void previsit( const ast::OneType * ) { visit_children = false; } 31 AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 32 : symtab( syms ), tenv( e ) {} 47 33 48 const ast::Type * postvisit( const ast::ArrayType * at ) { 49 return new ast::PointerType{ at->base, at->qualifiers }; 50 } 34 void previsit( const ast::VoidType * ) { visit_children = false; } 35 void previsit( const ast::BasicType * ) { visit_children = false; } 36 void previsit( const ast::PointerType * ) { visit_children = false; } 37 void previsit( const ast::ArrayType * ) { visit_children = false; } 38 void previsit( const ast::FunctionType * ) { visit_children = false; } 39 void previsit( const ast::StructInstType * ) { visit_children = false; } 40 void previsit( const ast::UnionInstType * ) { visit_children = false; } 41 void previsit( const ast::EnumInstType * ) { visit_children = false; } 42 void previsit( const ast::TraitInstType * ) { visit_children = false; } 43 void previsit( const ast::TypeInstType * ) { visit_children = false; } 44 void previsit( const ast::TupleType * ) { visit_children = false; } 45 void previsit( const ast::VarArgsType * ) { visit_children = false; } 46 void previsit( const ast::ZeroType * ) { visit_children = false; } 47 void previsit( const ast::OneType * ) { visit_children = false; } 51 48 52 const ast::Type * postvisit( const ast::FunctionType * ft ) {53 return new ast::PointerType{ ft };54 49 const ast::Type * postvisit( const ast::ArrayType * at ) { 50 return new ast::PointerType( at->base, at->qualifiers ); 51 } 55 52 56 const ast::Type * postvisit( const ast::TypeInstType * inst ) { 57 // replace known function-type-variables with pointer-to-function 58 if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) { 59 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) { 60 return new ast::PointerType{ inst }; 61 } 62 } else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) { 63 if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) { 64 if ( tyDecl->kind == ast::TypeDecl::Ftype ) { 65 return new ast::PointerType{ inst }; 66 } 53 const ast::Type * postvisit( const ast::FunctionType * ft ) { 54 return new ast::PointerType( ft ); 55 } 56 57 const ast::Type * postvisit( const ast::TypeInstType * inst ) { 58 // replace known function-type-variables with pointer-to-function 59 if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) { 60 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) { 61 return new ast::PointerType( inst ); 62 } 63 } else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) { 64 if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) { 65 if ( tyDecl->kind == ast::TypeDecl::Ftype ) { 66 return new ast::PointerType( inst ); 67 67 } 68 68 } 69 return inst;70 69 } 71 }; 70 return inst; 71 } 72 }; 73 72 74 } // anonymous namespace 73 75 -
src/ResolvExpr/CandidateFinder.cpp
r16e0dcb rf7f997a 751 751 const ast::Type * returnType = funcType->returns.front(); 752 752 if ( selfFinder.strictMode ) { 753 if ( ! 753 if ( !unifyExact( 754 754 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden() ) // xxx - is no widening correct? 755 755 ) { … … 757 757 return; 758 758 } 759 } 760 else { 761 if ( ! unify( 759 } else { 760 if ( !unify( 762 761 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen ) 763 762 ) { … … 1109 1108 intrinsicResult.emplace_back(std::move(withFunc)); 1110 1109 } 1111 } 1112 else { 1110 } else { 1113 1111 candidates.emplace_back( std::move( withFunc ) ); 1114 1112 } … … 1156 1154 1157 1155 for ( CandidateRef & r : finder.candidates ) { 1158 if ( ! 1156 if ( !isLvalue( r->expr ) ) continue; 1159 1157 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } ); 1160 1158 } -
src/ResolvExpr/CommonType.cc
r16e0dcb rf7f997a 343 343 ); 344 344 345 class CommonType final : public ast::WithShortCircuiting { 346 const ast::Type * type2; 347 WidenMode widen; 348 ast::TypeEnvironment & tenv; 349 const ast::OpenVarSet & open; 350 ast::AssertionSet & need; 351 ast::AssertionSet & have; 352 public: 353 static size_t traceId; 354 ast::ptr< ast::Type > result; 355 356 CommonType( 357 const ast::Type * t2, WidenMode w, 358 ast::TypeEnvironment & env, const ast::OpenVarSet & o, 359 ast::AssertionSet & need, ast::AssertionSet & have ) 360 : type2( t2 ), widen( w ), tenv( env ), open( o ), need (need), have (have) ,result() {} 361 362 void previsit( const ast::Node * ) { visit_children = false; } 363 364 void postvisit( const ast::VoidType * ) {} 365 366 void postvisit( const ast::BasicType * basic ) { 367 if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) { 368 ast::BasicType::Kind kind; 369 if (basic->kind != basic2->kind && !widen.first && !widen.second) return; 370 else if (!widen.first) kind = basic->kind; // widen.second 371 else if (!widen.second) kind = basic2->kind; 372 else kind = commonTypes[ basic->kind ][ basic2->kind ]; 373 // xxx - what does qualifiers even do here?? 374 if ( (basic->qualifiers >= basic2->qualifiers || widen.first) 375 && (basic->qualifiers <= basic2->qualifiers || widen.second) ) { 376 result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers }; 345 class CommonType final : public ast::WithShortCircuiting { 346 const ast::Type * type2; 347 WidenMode widen; 348 ast::TypeEnvironment & tenv; 349 const ast::OpenVarSet & open; 350 ast::AssertionSet & need; 351 ast::AssertionSet & have; 352 public: 353 static size_t traceId; 354 ast::ptr< ast::Type > result; 355 356 CommonType( 357 const ast::Type * t2, WidenMode w, 358 ast::TypeEnvironment & env, const ast::OpenVarSet & o, 359 ast::AssertionSet & need, ast::AssertionSet & have ) 360 : type2( t2 ), widen( w ), tenv( env ), open( o ), need (need), have (have) ,result() {} 361 362 void previsit( const ast::Node * ) { visit_children = false; } 363 364 void postvisit( const ast::VoidType * ) {} 365 366 void postvisit( const ast::BasicType * basic ) { 367 if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) { 368 ast::BasicType::Kind kind; 369 if (basic->kind != basic2->kind && !widen.first && !widen.second) return; 370 else if (!widen.first) kind = basic->kind; // widen.second 371 else if (!widen.second) kind = basic2->kind; 372 else kind = commonTypes[ basic->kind ][ basic2->kind ]; 373 // xxx - what does qualifiers even do here?? 374 if ( (basic->qualifiers >= basic2->qualifiers || widen.first) 375 && (basic->qualifiers <= basic2->qualifiers || widen.second) ) { 376 result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers }; 377 } 378 } else if ( 379 dynamic_cast< const ast::ZeroType * >( type2 ) 380 || dynamic_cast< const ast::OneType * >( type2 ) 381 ) { 382 if (widen.second) { 383 result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers }; 384 } 385 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { 386 const ast::EnumDecl* enumDecl = enumInst->base; 387 if ( enumDecl->base ) { 388 result = enumDecl->base.get(); 389 } else { 390 ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ]; 391 if ( 392 ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers ) 393 || widen.first ) 394 && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers ) 395 || widen.second ) 396 ) { 397 result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers }; 377 398 } 399 } 400 } 401 } 402 403 private: 404 template< typename Pointer > 405 void getCommonWithVoidPointer( const Pointer * voidPtr, const Pointer * oPtr ) { 406 const ast::Type * base = oPtr->base; 407 if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) { 408 auto entry = open.find( *var ); 409 if ( entry != open.end() ) { 410 ast::AssertionSet need, have; 411 if ( ! tenv.bindVar( 412 var, voidPtr->base, entry->second, need, have, open, widen ) 413 ) return; 414 } 415 } 416 result = voidPtr; 417 add_qualifiers( result, oPtr->qualifiers ); 418 } 419 420 // For a typed enum, we want to unify type1 with the base type of the enum 421 bool tryResolveWithTypedEnum( const ast::Type * type1 ) { 422 if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) { 423 ast::OpenVarSet newOpen{ open }; 424 if (enumInst->base->base 425 && unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen)) { 426 result = type1; 427 return true; 428 } 429 } 430 return false; 431 } 432 433 public: 434 void postvisit( const ast::PointerType * pointer ) { 435 if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) { 436 if ( 437 widen.first 438 && pointer2->base.as< ast::VoidType >() 439 && ! ast::isFtype( pointer->base ) 440 ) { 441 getCommonWithVoidPointer( pointer2, pointer ); 378 442 } else if ( 379 dynamic_cast< const ast::ZeroType * >( type2 ) 380 || dynamic_cast< const ast::OneType * >( type2 ) 443 widen.second 444 && pointer->base.as< ast::VoidType >() 445 && ! ast::isFtype( pointer2->base ) 381 446 ) { 382 if (widen.second) { 383 result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers }; 384 } 385 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { 386 const ast::EnumDecl* enumDecl = enumInst->base; 387 if ( enumDecl->base ) { 388 result = enumDecl->base.get(); 389 } else { 390 ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ]; 447 getCommonWithVoidPointer( pointer, pointer2 ); 448 } else if ( 449 ( pointer->base->qualifiers >= pointer2->base->qualifiers || widen.first ) 450 && ( pointer->base->qualifiers <= pointer2->base->qualifiers || widen.second ) 451 ) { 452 ast::CV::Qualifiers q1 = pointer->base->qualifiers; 453 ast::CV::Qualifiers q2 = pointer2->base->qualifiers; 454 455 // force t{1,2} to be cloned if their qualifiers must be stripped, so that 456 // pointer{,2}->base are unchanged 457 ast::ptr< ast::Type > t1{ pointer->base }, t2{ pointer2->base }; 458 reset_qualifiers( t1 ); 459 reset_qualifiers( t2 ); 460 461 ast::OpenVarSet newOpen{ open }; 462 if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) { 463 result = pointer; 464 if ( q1.val != q2.val ) { 465 // reset result->base->qualifiers to be union of two base qualifiers 466 strict_dynamic_cast< ast::PointerType * >( 467 result.get_and_mutate() 468 )->base.get_and_mutate()->qualifiers = q1 | q2; 469 } 470 } else if ( isFtype (t1) && isFtype (t2) ) { 471 auto f1 = t1.as<ast::FunctionType>(); 472 if (!f1) return; 473 auto f2 = t2.strict_as<ast::FunctionType>(); 474 475 assertf(f1->returns.size() <= 1, "Function return should not be a list"); 476 assertf(f2->returns.size() <= 1, "Function return should not be a list"); 477 391 478 if ( 392 ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers ) 393 || widen.first ) 394 && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers ) 395 || widen.second ) 396 ) { 397 result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers }; 479 ( f1->params.size() != f2->params.size() || f1->returns.size() != f2->returns.size() ) 480 && ! f1->isTtype() 481 && ! f2->isTtype() 482 ) return; 483 484 auto params1 = flattenList( f1->params, tenv ); 485 auto params2 = flattenList( f2->params, tenv ); 486 487 auto crnt1 = params1.begin(); 488 auto crnt2 = params2.begin(); 489 auto end1 = params1.end(); 490 auto end2 = params2.end(); 491 492 while (crnt1 != end1 && crnt2 != end2 ) { 493 const ast::Type * arg1 = *crnt1; 494 const ast::Type * arg2 = *crnt2; 495 496 bool isTuple1 = Tuples::isTtype( t1 ); 497 bool isTuple2 = Tuples::isTtype( t2 ); 498 499 // assumes here that ttype *must* be last parameter 500 if ( isTuple1 && ! isTuple2 ) { 501 // combine remainder of list2, then unify 502 if (unifyExact( 503 arg1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open, 504 noWiden() )) { 505 break; 506 } else return; 507 } else if ( ! isTuple1 && isTuple2 ) { 508 // combine remainder of list1, then unify 509 if (unifyExact( 510 tupleFromTypes( crnt1, end1 ), arg2, tenv, need, have, open, 511 noWiden() )) { 512 break; 513 } else return; 514 } 515 516 // allow qualifiers of pointer and reference base to become more specific 517 if (auto ref1 = dynamic_cast<const ast::ReferenceType *> (arg1)) { 518 if (auto ref2 = dynamic_cast<const ast::ReferenceType *> (arg2)) { 519 ast::ptr<ast::Type> base1 = ref1->base; 520 ast::ptr<ast::Type> base2 = ref2->base; 521 522 // xxx - assume LHS is always the target type 523 524 if ( ! ((widen.second && ref2->qualifiers.is_mutex) 525 || (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return; 526 527 if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) { 528 529 reset_qualifiers(base1); 530 reset_qualifiers(base2); 531 532 if ( !unifyExact( 533 base1, base2, tenv, need, have, open, noWiden() ) 534 ) return; 535 } 536 } else return; 537 } else if (auto ptr1 = dynamic_cast<const ast::PointerType *> (arg1)) { 538 if (auto ptr2 = dynamic_cast<const ast::PointerType *> (arg2)) { 539 ast::ptr<ast::Type> base1 = ptr1->base; 540 ast::ptr<ast::Type> base2 = ptr2->base; 541 542 // xxx - assume LHS is always the target type 543 // a function accepting const can always be called by non-const arg 544 545 if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) { 546 547 reset_qualifiers(base1); 548 reset_qualifiers(base2); 549 550 if ( ! unifyExact( 551 base1, base2, tenv, need, have, open, noWiden() ) 552 ) return; 553 } 554 } else return; 555 } else if (! unifyExact( 556 arg1, arg2, tenv, need, have, open, noWiden() )) { 557 return; 558 } 559 ++crnt1; ++crnt2; 560 } 561 if ( crnt1 != end1 ) { 562 // try unifying empty tuple with ttype 563 const ast::Type * t1 = *crnt1; 564 if (! Tuples::isTtype( t1 ) ) return; 565 if (! unifyExact( 566 t1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open, 567 noWiden() )) return; 568 } else if ( crnt2 != end2 ) { 569 // try unifying empty tuple with ttype 570 const ast::Type * t2 = *crnt2; 571 if ( !Tuples::isTtype( t2 ) ) return; 572 if ( !unifyExact( 573 tupleFromTypes( crnt1, end1 ), t2, tenv, need, have, open, 574 noWiden() )) return; 575 } 576 if ((f1->returns.size() == 0 && f2->returns.size() == 0) 577 || (f1->returns.size() == 1 && f2->returns.size() == 1 && unifyExact(f1->returns[0], f2->returns[0], tenv, need, have, open, noWiden()))) { 578 result = pointer; 579 580 for (auto & assn : f1->assertions) { 581 auto i = need.find(assn); 582 if (i != need.end()) i->second.isUsed = true; 583 auto j = have.find(assn); 584 if (j != have.end()) j->second.isUsed = true; 585 } 586 587 for (auto & assn : f2->assertions) { 588 auto i = need.find(assn); 589 if (i != need.end()) i->second.isUsed = true; 590 auto j = have.find(assn); 591 if (j != have.end()) j->second.isUsed = true; 592 } 593 } 594 } // if ftype 595 } 596 } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) { 597 result = pointer; 598 add_qualifiers( result, type2->qualifiers ); 599 } else { 600 tryResolveWithTypedEnum( pointer ); 601 } 602 } 603 604 void postvisit( const ast::ArrayType * arr ) { 605 // xxx - does it make sense? 606 tryResolveWithTypedEnum( arr ); 607 } 608 609 void postvisit( const ast::ReferenceType * ref ) { 610 if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) { 611 if ( 612 widen.first && ref2->base.as< ast::VoidType >() && ! ast::isFtype( ref->base ) 613 ) { 614 getCommonWithVoidPointer( ref2, ref ); 615 } else if ( 616 widen.second && ref->base.as< ast::VoidType>() && ! ast::isFtype( ref2->base ) 617 ) { 618 getCommonWithVoidPointer( ref, ref2 ); 619 } else if ( 620 ( ref->base->qualifiers >= ref2->base->qualifiers || widen.first ) 621 && ( ref->base->qualifiers <= ref2->base->qualifiers || widen.second ) 622 ) { 623 ast::CV::Qualifiers q1 = ref->base->qualifiers, q2 = ref2->base->qualifiers; 624 625 // force t{1,2} to be cloned if their qualifiers must be stripped, so that 626 // ref{,2}->base are unchanged 627 ast::ptr< ast::Type > t1{ ref->base }, t2{ ref2->base }; 628 reset_qualifiers( t1 ); 629 reset_qualifiers( t2 ); 630 631 ast::OpenVarSet newOpen{ open }; 632 if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) { 633 result = ref; 634 if ( q1.val != q2.val ) { 635 // reset result->base->qualifiers to be union of two base qualifiers 636 strict_dynamic_cast< ast::ReferenceType * >( 637 result.get_and_mutate() 638 )->base.get_and_mutate()->qualifiers = q1 | q2; 398 639 } 399 640 } 400 641 } 401 } 402 403 private: 404 template< typename Pointer > 405 void getCommonWithVoidPointer( const Pointer * voidPtr, const Pointer * oPtr ) { 406 const ast::Type * base = oPtr->base; 407 if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) { 408 auto entry = open.find( *var ); 409 if ( entry != open.end() ) { 410 ast::AssertionSet need, have; 411 if ( ! tenv.bindVar( 412 var, voidPtr->base, entry->second, need, have, open, widen ) 413 ) return; 414 } 415 } 416 result = voidPtr; 417 add_qualifiers( result, oPtr->qualifiers ); 418 } 419 420 // For a typed enum, we want to unify type1 with the base type of the enum 421 bool tryResolveWithTypedEnum( const ast::Type * type1 ) { 422 if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) { 423 ast::OpenVarSet newOpen{ open }; 424 if (enumInst->base->base 425 && unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen)) { 426 result = type1; 427 return true; 428 } 429 } 430 return false; 431 } 432 433 public: 434 void postvisit( const ast::PointerType * pointer ) { 435 if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) { 436 if ( 437 widen.first 438 && pointer2->base.as< ast::VoidType >() 439 && ! ast::isFtype( pointer->base ) 440 ) { 441 getCommonWithVoidPointer( pointer2, pointer ); 442 } else if ( 443 widen.second 444 && pointer->base.as< ast::VoidType >() 445 && ! ast::isFtype( pointer2->base ) 446 ) { 447 getCommonWithVoidPointer( pointer, pointer2 ); 448 } else if ( 449 ( pointer->base->qualifiers >= pointer2->base->qualifiers || widen.first ) 450 && ( pointer->base->qualifiers <= pointer2->base->qualifiers || widen.second ) 451 ) { 452 ast::CV::Qualifiers q1 = pointer->base->qualifiers; 453 ast::CV::Qualifiers q2 = pointer2->base->qualifiers; 454 455 // force t{1,2} to be cloned if their qualifiers must be stripped, so that 456 // pointer{,2}->base are unchanged 457 ast::ptr< ast::Type > t1{ pointer->base }, t2{ pointer2->base }; 458 reset_qualifiers( t1 ); 459 reset_qualifiers( t2 ); 460 461 ast::OpenVarSet newOpen{ open }; 462 if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) { 463 result = pointer; 464 if ( q1.val != q2.val ) { 465 // reset result->base->qualifiers to be union of two base qualifiers 466 strict_dynamic_cast< ast::PointerType * >( 467 result.get_and_mutate() 468 )->base.get_and_mutate()->qualifiers = q1 | q2; 469 } 470 } 471 else if ( isFtype (t1) && isFtype (t2) ) { 472 auto f1 = t1.as<ast::FunctionType>(); 473 if (!f1) return; 474 auto f2 = t2.strict_as<ast::FunctionType>(); 475 476 assertf(f1->returns.size() <= 1, "Function return should not be a list"); 477 assertf(f2->returns.size() <= 1, "Function return should not be a list"); 478 479 if ( 480 ( f1->params.size() != f2->params.size() || f1->returns.size() != f2->returns.size() ) 481 && ! f1->isTtype() 482 && ! f2->isTtype() 483 ) return; 484 485 auto params1 = flattenList( f1->params, tenv ); 486 auto params2 = flattenList( f2->params, tenv ); 487 488 auto crnt1 = params1.begin(); 489 auto crnt2 = params2.begin(); 490 auto end1 = params1.end(); 491 auto end2 = params2.end(); 492 493 while (crnt1 != end1 && crnt2 != end2 ) { 494 const ast::Type * arg1 = *crnt1; 495 const ast::Type * arg2 = *crnt2; 496 497 bool isTuple1 = Tuples::isTtype( t1 ); 498 bool isTuple2 = Tuples::isTtype( t2 ); 499 500 // assumes here that ttype *must* be last parameter 501 if ( isTuple1 && ! isTuple2 ) { 502 // combine remainder of list2, then unify 503 if (unifyExact( 504 arg1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open, 505 noWiden() )) { 506 break; 507 508 } 509 else return; 510 } else if ( ! isTuple1 && isTuple2 ) { 511 // combine remainder of list1, then unify 512 if (unifyExact( 513 tupleFromTypes( crnt1, end1 ), arg2, tenv, need, have, open, 514 noWiden() )) { 515 break; 516 517 } 518 else return; 519 } 520 521 // allow qualifiers of pointer and reference base to become more specific 522 if (auto ref1 = dynamic_cast<const ast::ReferenceType *> (arg1)) { 523 if (auto ref2 = dynamic_cast<const ast::ReferenceType *> (arg2)) { 524 ast::ptr<ast::Type> base1 = ref1->base; 525 ast::ptr<ast::Type> base2 = ref2->base; 526 527 // xxx - assume LHS is always the target type 528 529 if ( ! ((widen.second && ref2->qualifiers.is_mutex) 530 || (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return; 531 532 if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) { 533 534 reset_qualifiers(base1); 535 reset_qualifiers(base2); 536 537 if ( ! unifyExact( 538 base1, base2, tenv, need, have, open, noWiden() ) 539 ) return; 540 } 541 } 542 else return; 543 } 544 else if (auto ptr1 = dynamic_cast<const ast::PointerType *> (arg1)) { 545 if (auto ptr2 = dynamic_cast<const ast::PointerType *> (arg2)) { 546 ast::ptr<ast::Type> base1 = ptr1->base; 547 ast::ptr<ast::Type> base2 = ptr2->base; 548 549 // xxx - assume LHS is always the target type 550 // a function accepting const can always be called by non-const arg 551 552 if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) { 553 554 reset_qualifiers(base1); 555 reset_qualifiers(base2); 556 557 if ( ! unifyExact( 558 base1, base2, tenv, need, have, open, noWiden() ) 559 ) return; 560 } 561 } 562 else return; 563 564 } 565 else if (! unifyExact( 566 arg1, arg2, tenv, need, have, open, noWiden() )) return; 567 568 ++crnt1; ++crnt2; 569 } 570 if ( crnt1 != end1 ) { 571 // try unifying empty tuple with ttype 572 const ast::Type * t1 = *crnt1; 573 if (! Tuples::isTtype( t1 ) ) return; 574 if (! unifyExact( 575 t1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open, 576 noWiden() )) return; 577 } else if ( crnt2 != end2 ) { 578 // try unifying empty tuple with ttype 579 const ast::Type * t2 = *crnt2; 580 if (! Tuples::isTtype( t2 ) ) return; 581 if (! unifyExact( 582 tupleFromTypes( crnt1, end1 ), t2, tenv, need, have, open, 583 noWiden() )) return; 584 } 585 if ((f1->returns.size() == 0 && f2->returns.size() == 0) 586 || (f1->returns.size() == 1 && f2->returns.size() == 1 && unifyExact(f1->returns[0], f2->returns[0], tenv, need, have, open, noWiden()))) { 587 result = pointer; 588 589 for (auto & assn : f1->assertions) { 590 auto i = need.find(assn); 591 if (i != need.end()) i->second.isUsed = true; 592 auto j = have.find(assn); 593 if (j != have.end()) j->second.isUsed = true; 594 } 595 596 for (auto & assn : f2->assertions) { 597 auto i = need.find(assn); 598 if (i != need.end()) i->second.isUsed = true; 599 auto j = have.find(assn); 600 if (j != have.end()) j->second.isUsed = true; 601 } 602 603 } 604 } // if ftype 605 606 } 607 } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) { 608 result = pointer; 609 add_qualifiers( result, type2->qualifiers ); 642 } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) { 643 result = ref; 644 add_qualifiers( result, type2->qualifiers ); 645 } else { 646 if (!dynamic_cast<const ast::EnumInstType *>(type2)) 647 result = commonType( type2, ref, tenv, need, have, open, widen ); 648 } 649 } 650 651 void postvisit( const ast::FunctionType * func) { 652 tryResolveWithTypedEnum( func ); 653 } 654 655 void postvisit( const ast::StructInstType * inst ) { 656 tryResolveWithTypedEnum( inst ); 657 } 658 659 void postvisit( const ast::UnionInstType * inst ) { 660 tryResolveWithTypedEnum( inst ); 661 } 662 663 void postvisit( const ast::EnumInstType * enumInst ) { 664 if (!dynamic_cast<const ast::EnumInstType *>(type2)) 665 result = commonType( type2, enumInst, tenv, need, have, open, widen); 666 } 667 668 void postvisit( const ast::TraitInstType * ) {} 669 670 void postvisit( const ast::TypeInstType * ) {} 671 672 void postvisit( const ast::TupleType * tuple ) { 673 tryResolveWithTypedEnum( tuple ); 674 } 675 676 void postvisit( const ast::VarArgsType * ) {} 677 678 void postvisit( const ast::ZeroType * zero ) { 679 if ( !widen.first ) return; 680 if ( dynamic_cast< const ast::BasicType * >( type2 ) 681 || dynamic_cast< const ast::PointerType * >( type2 ) ) { 682 if ( widen.second || zero->qualifiers <= type2->qualifiers ) { 683 result = type2; 684 add_qualifiers( result, zero->qualifiers ); 685 } 686 } else if ( widen.second && dynamic_cast< const ast::OneType * >( type2 ) ) { 687 result = new ast::BasicType{ 688 ast::BasicType::SignedInt, zero->qualifiers | type2->qualifiers }; 689 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { 690 const ast::EnumDecl * enumDecl = enumInst->base; 691 if ( enumDecl->base ) { 692 if ( tryResolveWithTypedEnum( zero ) ) 693 add_qualifiers( result, zero->qualifiers ); 610 694 } else { 611 tryResolveWithTypedEnum( pointer );612 }613 }614 615 void postvisit( const ast::ArrayType * arr ) {616 // xxx - does it make sense?617 tryResolveWithTypedEnum( arr );618 }619 620 void postvisit( const ast::ReferenceType * ref ) {621 if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {622 if (623 widen.first && ref2->base.as< ast::VoidType >() && ! ast::isFtype( ref->base )624 ) {625 getCommonWithVoidPointer( ref2, ref );626 } else if (627 widen.second && ref->base.as< ast::VoidType>() && ! ast::isFtype( ref2->base )628 ) {629 getCommonWithVoidPointer( ref, ref2 );630 } else if (631 ( ref->base->qualifiers >= ref2->base->qualifiers || widen.first )632 && ( ref->base->qualifiers <= ref2->base->qualifiers || widen.second )633 ) {634 ast::CV::Qualifiers q1 = ref->base->qualifiers, q2 = ref2->base->qualifiers;635 636 // force t{1,2} to be cloned if their qualifiers must be stripped, so that637 // ref{,2}->base are unchanged638 ast::ptr< ast::Type > t1{ ref->base }, t2{ ref2->base };639 reset_qualifiers( t1 );640 reset_qualifiers( t2 );641 642 ast::OpenVarSet newOpen{ open };643 if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) {644 result = ref;645 if ( q1.val != q2.val ) {646 // reset result->base->qualifiers to be union of two base qualifiers647 strict_dynamic_cast< ast::ReferenceType * >(648 result.get_and_mutate()649 )->base.get_and_mutate()->qualifiers = q1 | q2;650 }651 }652 }653 } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {654 result = ref;655 add_qualifiers( result, type2->qualifiers );656 } else {657 if (!dynamic_cast<const ast::EnumInstType *>(type2))658 result = commonType( type2, ref, tenv, need, have, open, widen );659 }660 }661 662 void postvisit( const ast::FunctionType * func) {663 tryResolveWithTypedEnum( func );664 }665 666 void postvisit( const ast::StructInstType * inst ) {667 tryResolveWithTypedEnum( inst );668 }669 670 void postvisit( const ast::UnionInstType * inst ) {671 tryResolveWithTypedEnum( inst );672 }673 674 void postvisit( const ast::EnumInstType * enumInst ) {675 if (!dynamic_cast<const ast::EnumInstType *>(type2))676 result = commonType( type2, enumInst, tenv, need, have, open, widen);677 }678 679 void postvisit( const ast::TraitInstType * ) {}680 681 void postvisit( const ast::TypeInstType * ) {}682 683 void postvisit( const ast::TupleType * tuple ) {684 tryResolveWithTypedEnum( tuple );685 }686 687 void postvisit( const ast::VarArgsType * ) {}688 689 void postvisit( const ast::ZeroType * zero ) {690 if ( ! widen.first ) return;691 if ( dynamic_cast< const ast::BasicType * >( type2 )692 || dynamic_cast< const ast::PointerType * >( type2 ) ) {693 695 if ( widen.second || zero->qualifiers <= type2->qualifiers ) { 694 696 result = type2; 695 697 add_qualifiers( result, zero->qualifiers ); 696 698 } 697 } else if ( widen.second && dynamic_cast< const ast::OneType * >( type2 ) ) {698 result = new ast::BasicType{699 ast::BasicType::SignedInt, zero->qualifiers | type2->qualifiers };700 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { 701 const ast::EnumDecl * enumDecl = enumInst->base;702 if ( enumDecl->base ) {703 if ( tryResolveWithTypedEnum( zero ) )704 add_qualifiers( result, zero->qualifiers );705 } else {706 if ( widen.second || zero->qualifiers <= type2->qualifiers ) {707 result = type2;708 add_qualifiers( result, zero->qualifiers );709 }710 }711 }712 }713 714 void postvisit( const ast::OneType * one ) {715 if ( ! widen.first ) return;716 if ( dynamic_cast< const ast::BasicType * >( type2 ) ){699 } 700 } 701 } 702 703 void postvisit( const ast::OneType * one ) { 704 if ( !widen.first ) return; 705 if ( dynamic_cast< const ast::BasicType * >( type2 ) ) { 706 if ( widen.second || one->qualifiers <= type2->qualifiers ) { 707 result = type2; 708 add_qualifiers( result, one->qualifiers ); 709 } 710 } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) { 711 result = new ast::BasicType{ 712 ast::BasicType::SignedInt, one->qualifiers | type2->qualifiers }; 713 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { 714 const ast::EnumDecl * enumBase = enumInst->base; 715 if ( enumBase->base ) { 716 if ( tryResolveWithTypedEnum( one )) 717 add_qualifiers( result, one->qualifiers ); 718 } else { 717 719 if ( widen.second || one->qualifiers <= type2->qualifiers ) { 718 720 result = type2; 719 721 add_qualifiers( result, one->qualifiers ); 720 722 } 721 } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) { 722 result = new ast::BasicType{ 723 ast::BasicType::SignedInt, one->qualifiers | type2->qualifiers }; 724 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { 725 const ast::EnumDecl * enumBase = enumInst->base; 726 if ( enumBase->base ) { 727 if ( tryResolveWithTypedEnum( one )) 728 add_qualifiers( result, one->qualifiers ); 729 } else { 730 if ( widen.second || one->qualifiers <= type2->qualifiers ) { 731 result = type2; 732 add_qualifiers( result, one->qualifiers ); 733 } 734 } 735 } 736 } 737 738 }; 739 740 // size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType"); 741 namespace { 742 ast::ptr< ast::Type > handleReference( 743 const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen, 744 ast::TypeEnvironment & env, 745 const ast::OpenVarSet & open 746 ) { 747 ast::ptr<ast::Type> common; 748 ast::AssertionSet have, need; 749 ast::OpenVarSet newOpen{ open }; 750 751 // need unify to bind type variables 752 if ( unify( t1, t2, env, have, need, newOpen, common ) ) { 753 ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers; 723 } 724 } 725 } 726 }; 727 728 // size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType"); 729 730 namespace { 731 ast::ptr< ast::Type > handleReference( 732 const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen, 733 ast::TypeEnvironment & env, 734 const ast::OpenVarSet & open 735 ) { 736 ast::ptr<ast::Type> common; 737 ast::AssertionSet have, need; 738 ast::OpenVarSet newOpen{ open }; 739 740 // need unify to bind type variables 741 if ( unify( t1, t2, env, have, need, newOpen, common ) ) { 742 ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers; 743 PRINT( 744 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl; 745 ) 746 if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) { 754 747 PRINT( 755 std::cerr << " unify success: " << widenFirst << " " << widenSecond<< std::endl;748 std::cerr << "widen okay" << std::endl; 756 749 ) 757 if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) { 758 PRINT( 759 std::cerr << "widen okay" << std::endl; 760 ) 761 add_qualifiers( common, q1 | q2 ); 762 return common; 763 } 764 } 765 750 add_qualifiers( common, q1 | q2 ); 751 return common; 752 } 753 } 754 755 PRINT( 756 std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl; 757 ) 758 return { nullptr }; 759 } 760 } 761 762 ast::ptr< ast::Type > commonType( 763 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, 764 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 765 const ast::OpenVarSet & open, WidenMode widen 766 ) { 767 unsigned depth1 = type1->referenceDepth(); 768 unsigned depth2 = type2->referenceDepth(); 769 770 if ( depth1 != depth2 ) { // implies depth1 > 0 || depth2 > 0 771 PRINT( 772 std::cerr << "reference depth diff: " << (depth1-depth2) << std::endl; 773 ) 774 ast::ptr< ast::Type > result; 775 const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >(); 776 const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >(); 777 778 if ( depth1 > depth2 ) { 779 assert( ref1 ); 780 result = handleReference( ref1->base, type2, widen, env, open ); 781 } else { // Implies depth1 < depth2 782 assert( ref2 ); 783 result = handleReference( type1, ref2->base, widen, env, open ); 784 } 785 786 if ( result && ref1 ) { 787 // formal is reference, so result should be reference 766 788 PRINT( 767 std::cerr << " exact unify failed: " << t1 << " " << t2<< std::endl;789 std::cerr << "formal is reference; result should be reference" << std::endl; 768 790 ) 769 return { nullptr }; 770 } 771 } 772 773 ast::ptr< ast::Type > commonType( 774 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, 775 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 776 const ast::OpenVarSet & open, WidenMode widen 777 ) { 778 unsigned depth1 = type1->referenceDepth(); 779 unsigned depth2 = type2->referenceDepth(); 780 781 if ( depth1 != depth2 ) { // implies depth1 > 0 || depth2 > 0 782 PRINT( 783 std::cerr << "reference depth diff: " << (depth1-depth2) << std::endl; 784 ) 785 ast::ptr< ast::Type > result; 786 const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >(); 787 const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >(); 788 789 if ( depth1 > depth2 ) { 790 assert( ref1 ); 791 result = handleReference( ref1->base, type2, widen, env, open ); 792 } else { // implies depth1 < depth2 793 assert( ref2 ); 794 result = handleReference( type1, ref2->base, widen, env, open ); 795 } 796 797 if ( result && ref1 ) { 798 // formal is reference, so result should be reference 799 PRINT( 800 std::cerr << "formal is reference; result should be reference" << std::endl; 801 ) 802 result = new ast::ReferenceType{ result, ref1->qualifiers }; 803 } 804 805 PRINT( 806 std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is " 807 "[" << result << "]" << std::endl; 808 ) 809 return result; 810 } 811 // otherwise both are reference types of the same depth and this is handled by the visitor 812 ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have }; 813 type1->accept( visitor ); 814 // ast::ptr< ast::Type > result = visitor.core.result; 815 816 return visitor.core.result; 817 } 791 result = new ast::ReferenceType{ result, ref1->qualifiers }; 792 } 793 794 PRINT( 795 std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is " 796 "[" << result << "]" << std::endl; 797 ) 798 return result; 799 } 800 // otherwise both are reference types of the same depth and this is handled by the visitor 801 ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have }; 802 type1->accept( visitor ); 803 // ast::ptr< ast::Type > result = visitor.core.result; 804 805 return visitor.core.result; 806 } 818 807 819 808 } // namespace ResolvExpr -
src/ResolvExpr/Cost.h
r16e0dcb rf7f997a 21 21 22 22 namespace ResolvExpr { 23 // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the24 // specialization cost is a negative value so a correction is needed is a few places.25 23 26 class Cost { 27 union { 28 struct { 29 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 30 // Little-endian => first value is low priority and last is high priority. 31 unsigned char padding; ///< unused 32 unsigned char referenceCost; ///< reference conversions 33 unsigned char specCost; ///< Polymorphic type specializations (type assertions), negative cost 34 unsigned char varCost; ///< Count of polymorphic type variables 35 unsigned char signCost; ///< Count of safe sign conversions 36 unsigned char safeCost; ///< Safe (widening) conversions 37 unsigned char polyCost; ///< Count of parameters and return values bound to some poly type 38 unsigned char unsafeCost; ///< Unsafe (narrowing) conversions 39 #else 40 #error Cost BIG_ENDIAN unsupported 41 #endif 42 } v; 43 uint64_t all; 24 // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the 25 // specialization cost is a negative value so a correction is needed is a few places. 26 27 class Cost { 28 union { 29 struct { 30 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 31 // Little-endian => first value is low priority and last is high priority. 32 unsigned char padding; ///< unused 33 unsigned char referenceCost; ///< reference conversions 34 unsigned char specCost; ///< Polymorphic type specializations (type assertions), negative cost 35 unsigned char varCost; ///< Count of polymorphic type variables 36 unsigned char signCost; ///< Count of safe sign conversions 37 unsigned char safeCost; ///< Safe (widening) conversions 38 unsigned char polyCost; ///< Count of parameters and return values bound to some poly type 39 unsigned char unsafeCost; ///< Unsafe (narrowing) conversions 40 #else 41 #error Cost BIG_ENDIAN unsupported 42 #endif 43 } v; 44 uint64_t all; 45 }; 46 static const unsigned char correctb = 0xff; // byte correction for negative spec cost 47 static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost 48 public: 49 // Compiler adjusts constants for correct endian. 50 enum : uint64_t { 51 zero = 0x00'00'00'00'00'ff'00'00, 52 infinity = 0xff'ff'ff'ff'ff'00'ff'ff, 53 unsafe = 0x01'00'00'00'00'ff'00'00, 54 poly = 0x00'01'00'00'00'ff'00'00, 55 safe = 0x00'00'01'00'00'ff'00'00, 56 sign = 0x00'00'00'01'00'ff'00'00, 57 var = 0x00'00'00'00'01'ff'00'00, 58 spec = 0x00'00'00'00'00'fe'00'00, 59 reference = 0x00'00'00'00'00'ff'01'00, 60 }; //' 61 62 Cost( uint64_t all ) { Cost::all = all; } 63 Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) { 64 // Assume little-endian => first value is low priority and last is high priority. 65 v = { 66 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 67 (unsigned char)0, // padding 68 (unsigned char)referenceCost, // low priority 69 (unsigned char)(specCost + correctb), // correct for signedness 70 (unsigned char)varCost, 71 (unsigned char)signCost, 72 (unsigned char)safeCost, 73 (unsigned char)polyCost, 74 (unsigned char)unsafeCost, // high priority 75 #else 76 #error Cost BIG_ENDIAN unsupported 77 #endif 44 78 }; 45 static const unsigned char correctb = 0xff; // byte correction for negative spec cost 46 static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost 47 public: 48 // Compiler adjusts constants for correct endian. 49 enum : uint64_t { 50 zero = 0x00'00'00'00'00'ff'00'00, 51 infinity = 0xff'ff'ff'ff'ff'00'ff'ff, 52 unsafe = 0x01'00'00'00'00'ff'00'00, 53 poly = 0x00'01'00'00'00'ff'00'00, 54 safe = 0x00'00'01'00'00'ff'00'00, 55 sign = 0x00'00'00'01'00'ff'00'00, 56 var = 0x00'00'00'00'01'ff'00'00, 57 spec = 0x00'00'00'00'00'fe'00'00, 58 reference = 0x00'00'00'00'00'ff'01'00, 59 }; //' 79 } 60 80 61 Cost( uint64_t all ) { Cost::all = all; } 62 Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) { 63 // Assume little-endian => first value is low priority and last is high priority. 64 v = { 65 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 66 (unsigned char)0, // padding 67 (unsigned char)referenceCost, // low priority 68 (unsigned char)(specCost + correctb), // correct for signedness 69 (unsigned char)varCost, 70 (unsigned char)signCost, 71 (unsigned char)safeCost, 72 (unsigned char)polyCost, 73 (unsigned char)unsafeCost, // high priority 74 #else 75 #error Cost BIG_ENDIAN unsupported 76 #endif 77 }; 78 } 81 int get_unsafeCost() const { return v.unsafeCost; } 82 int get_polyCost() const { return v.polyCost; } 83 int get_safeCost() const { return v.safeCost; } 84 int get_signCost() const { return v.signCost; } 85 int get_varCost() const { return v.varCost; } 86 int get_specCost() const { return -(correctb - v.specCost); } 87 int get_referenceCost() const { return v.referenceCost; } 79 88 80 int get_unsafeCost() const { return v.unsafeCost; } 81 int get_polyCost() const { return v.polyCost; } 82 int get_safeCost() const { return v.safeCost; } 83 int get_signCost() const { return v.signCost; } 84 int get_varCost() const { return v.varCost; } 85 int get_specCost() const { return -(correctb - v.specCost); } 86 int get_referenceCost() const { return v.referenceCost; } 89 friend bool operator==( const Cost, const Cost ); 90 friend bool operator!=( const Cost lhs, const Cost rhs ); 91 // returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs 92 int compare( const Cost rhs ) const { 93 if ( all == infinity ) return 1; 94 if ( rhs.all == infinity ) return -1; 95 return all > rhs.all ? 1 : all == rhs.all ? 0 : -1; 96 } 97 friend bool operator<( const Cost lhs, const Cost rhs ); 87 98 88 friend bool operator==( const Cost, const Cost ); 89 friend bool operator!=( const Cost lhs, const Cost rhs ); 90 // returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs 91 int compare( const Cost rhs ) const { 92 if ( all == infinity ) return 1; 93 if ( rhs.all == infinity ) return -1; 94 return all > rhs.all ? 1 : all == rhs.all ? 0 : -1; 95 } 96 friend bool operator<( const Cost lhs, const Cost rhs ); 99 friend Cost operator+( const Cost lhs, const Cost rhs ); 97 100 98 friend Cost operator+( const Cost lhs, const Cost rhs ); 99 100 Cost operator+=( const Cost rhs ) { 101 if ( all == infinity ) return *this; 102 if ( rhs.all == infinity ) { 103 all = infinity; 104 return *this; 105 } 106 all += rhs.all - correctw; // correct for negative spec cost 101 Cost operator+=( const Cost rhs ) { 102 if ( all == infinity ) return *this; 103 if ( rhs.all == infinity ) { 104 all = infinity; 107 105 return *this; 108 106 } 109 110 Cost incUnsafe( int inc = 1 ) { 111 if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; } 112 return *this; 113 } 114 115 Cost incPoly( int inc = 1 ) { 116 if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; } 117 return *this; 118 } 119 120 Cost incSafe( int inc = 1 ) { 121 if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; } 122 return *this; 123 } 124 125 Cost incSign( int inc = 1 ) { 126 if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; } 127 return *this; 128 } 129 130 Cost incVar( int inc = 1 ) { 131 if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; } 132 return *this; 133 } 134 135 Cost decSpec( int dec = 1 ) { 136 if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; } 137 return *this; 138 } 139 140 Cost incReference( int inc = 1 ) { 141 if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; } 142 return *this; 143 } 144 145 friend std::ostream & operator<<( std::ostream & os, const Cost cost ); 146 }; 147 148 inline bool operator==( const Cost lhs, const Cost rhs ) { 149 return lhs.all == rhs.all; 107 all += rhs.all - correctw; // correct for negative spec cost 108 return *this; 150 109 } 151 110 152 inline bool operator!=( const Cost lhs, const Cost rhs ) { 153 return !( lhs.all == rhs.all ); 111 Cost incUnsafe( int inc = 1 ) { 112 if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; } 113 return *this; 154 114 } 155 115 156 inline bool operator<( const Cost lhs, const Cost rhs ) { 157 if ( lhs.all == Cost::infinity ) return false; 158 if ( rhs.all == Cost::infinity ) return true; 159 return lhs.all < rhs.all; 116 Cost incPoly( int inc = 1 ) { 117 if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; } 118 return *this; 160 119 } 161 120 162 inline Cost operator+( const Cost lhs, const Cost rhs) {163 if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity };164 return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost121 Cost incSafe( int inc = 1 ) { 122 if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; } 123 return *this; 165 124 } 166 125 167 inline std::ostream & operator<<( std::ostream & os, const Cost cost ) { 168 return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost() 169 << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost() 170 << ", " << cost.get_referenceCost() << " )"; 126 Cost incSign( int inc = 1 ) { 127 if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; } 128 return *this; 171 129 } 130 131 Cost incVar( int inc = 1 ) { 132 if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; } 133 return *this; 134 } 135 136 Cost decSpec( int dec = 1 ) { 137 if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; } 138 return *this; 139 } 140 141 Cost incReference( int inc = 1 ) { 142 if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; } 143 return *this; 144 } 145 146 friend std::ostream & operator<<( std::ostream & os, const Cost cost ); 147 }; 148 149 inline bool operator==( const Cost lhs, const Cost rhs ) { 150 return lhs.all == rhs.all; 151 } 152 153 inline bool operator!=( const Cost lhs, const Cost rhs ) { 154 return !( lhs.all == rhs.all ); 155 } 156 157 inline bool operator<( const Cost lhs, const Cost rhs ) { 158 if ( lhs.all == Cost::infinity ) return false; 159 if ( rhs.all == Cost::infinity ) return true; 160 return lhs.all < rhs.all; 161 } 162 163 inline Cost operator+( const Cost lhs, const Cost rhs ) { 164 if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity }; 165 return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost 166 } 167 168 inline std::ostream & operator<<( std::ostream & os, const Cost cost ) { 169 return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost() 170 << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost() 171 << ", " << cost.get_referenceCost() << " )"; 172 } 173 172 174 } // namespace ResolvExpr 173 175 -
src/ResolvExpr/CurrentObject.cc
r16e0dcb rf7f997a 41 41 42 42 namespace ast { 43 /// Iterates members of a type by initializer. 44 class MemberIterator { 45 public: 46 virtual ~MemberIterator() {} 47 48 /// Internal set position based on iterator ranges. 49 virtual void setPosition( 50 std::deque< ptr< Expr > >::const_iterator it, 51 std::deque< ptr< Expr > >::const_iterator end ) = 0; 52 53 /// Walks the current object using the given designators as a guide. 54 void setPosition( const std::deque< ptr< Expr > > & designators ) { 55 setPosition( designators.begin(), designators.end() ); 56 } 57 58 /// Retrieve the list of possible (Type,Designation) pairs for the 59 /// current position in the current object. 60 virtual std::deque< InitAlternative > operator* () const = 0; 61 62 /// True if the iterator is not currently at the end. 63 virtual operator bool() const = 0; 64 65 /// Moves the iterator by one member in the current object. 66 virtual MemberIterator & bigStep() = 0; 67 68 /// Moves the iterator by one member in the current subobject. 69 virtual MemberIterator & smallStep() = 0; 70 71 /// The type of the current object. 72 virtual const Type * getType() = 0; 73 74 /// The type of the current subobject. 75 virtual const Type * getNext() = 0; 76 77 /// Helper for operator*; aggregates must add designator to each init 78 /// alternative, but adding designators in operator* creates duplicates. 79 virtual std::deque< InitAlternative > first() const = 0; 80 }; 81 82 /// create a new MemberIterator that traverses a type correctly 83 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ); 84 85 /// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry 86 class SimpleIterator final : public MemberIterator { 87 CodeLocation location; 88 const Type * type = nullptr; 89 public: 90 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {} 91 92 void setPosition( 93 std::deque< ptr< Expr > >::const_iterator begin, 94 std::deque< ptr< Expr > >::const_iterator end 95 ) override { 96 if ( begin != end ) { 97 SemanticError( location, "Un-designated initializer given non-empty designator" ); 98 } 99 } 100 101 std::deque< InitAlternative > operator* () const override { return first(); } 102 103 operator bool() const override { return type; } 104 105 SimpleIterator & bigStep() override { return smallStep(); } 106 SimpleIterator & smallStep() override { 107 type = nullptr; // empty on increment because no members 108 return *this; 109 } 110 111 const Type * getType() override { return type; } 112 113 const Type * getNext() override { return type; } 114 115 std::deque< InitAlternative > first() const override { 116 if ( type ) return { InitAlternative{ type, new Designation{ location } } }; 117 return {}; 118 } 119 }; 120 121 /// Iterates over an indexed type: 122 class IndexIterator : public MemberIterator { 123 protected: 124 CodeLocation location; 125 size_t index = 0; 126 size_t size = 0; 127 std::unique_ptr<MemberIterator> memberIter; 128 public: 129 IndexIterator( const CodeLocation & loc, size_t size ) : 130 location( loc ), size( size ) 131 {} 132 133 void setPosition( const Expr * expr ) { 134 // need to permit integer-constant-expressions, including: integer constants, 135 // enumeration constants, character constants, sizeof expressions, alignof expressions, 136 // cast expressions 137 138 auto arg = eval( expr ); 139 assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" ); 140 index = arg.knownValue; 141 142 // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { 143 // try { 144 // index = constExpr->intValue(); 145 // } catch ( SemanticErrorException & ) { 146 // SemanticError( expr, "Constant expression of non-integral type in array designator: " ); 147 // } 148 // } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) { 149 // setPosition( castExpr->arg ); 150 // } else if ( dynamic_cast< const SizeofExpr * >( expr ) || dynamic_cast< const AlignofExpr * >( expr ) ) { 151 // index = 0; 152 // } else { 153 // assertf( false, "2 bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 154 // } 155 } 156 157 void setPosition( 158 std::deque<ast::ptr<ast::Expr>>::const_iterator begin, 159 std::deque<ast::ptr<ast::Expr>>::const_iterator end 160 ) override { 161 if ( begin == end ) return; 162 163 setPosition( *begin ); 164 memberIter->setPosition( ++begin, end ); 165 } 166 167 std::deque< InitAlternative > operator* () const override { return first(); } 168 169 operator bool() const override { return index < size; } 170 }; 171 172 /// Iterates over the members of array types: 173 class ArrayIterator final : public IndexIterator { 174 const ArrayType * array = nullptr; 175 const Type * base = nullptr; 176 177 size_t getSize( const Expr * expr ) { 178 auto res = eval( expr ); 179 if ( !res.hasKnownValue ) { 180 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) ); 181 } 182 return res.knownValue; 183 } 184 185 public: 186 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) : 187 IndexIterator( loc, getSize( at->dimension) ), 188 array( at ), base( at->base ) { 189 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) 190 memberIter.reset( createMemberIterator( loc, base ) ); 191 if ( at->isVarLen ) { 192 SemanticError( location, at, "VLA initialization does not support @=: " ); 193 } 194 } 195 196 ArrayIterator & bigStep() override { 197 PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 198 ++index; 199 memberIter.reset( index < size ? createMemberIterator( location, base ) : nullptr ); 200 return *this; 201 } 202 203 ArrayIterator & smallStep() override { 204 PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 205 if ( memberIter ) { 206 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; ) 207 memberIter->smallStep(); 208 if ( *memberIter ) { 209 PRINT( std::cerr << "has valid member iter" << std::endl; ) 210 return *this; 211 } 212 } 213 return bigStep(); 214 } 215 216 const Type * getType() override { return array; } 217 218 const Type * getNext() override { return base; } 219 220 std::deque< InitAlternative > first() const override { 221 PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 222 if ( memberIter && *memberIter ) { 223 std::deque< InitAlternative > ret = memberIter->first(); 224 for ( InitAlternative & alt : ret ) { 225 alt.designation.get_and_mutate()->designators.emplace_front( ConstantExpr::from_ulong( location, index ) ); 226 } 227 return ret; 228 } 229 return {}; 230 } 231 }; 232 233 class AggregateIterator : public MemberIterator { 234 protected: 235 using MemberList = std::vector< ptr< Decl > >; 236 237 CodeLocation location; 238 std::string kind; // for debug 239 std::string name; 240 const Type * inst; 241 const MemberList & members; 242 MemberList::const_iterator curMember; 243 bool atbegin = true; // false at first {small,big}Step 244 const Type * curType = nullptr; 245 std::unique_ptr< MemberIterator > memberIter = nullptr; 246 TypeSubstitution sub; 247 248 bool init() { 249 PRINT( std::cerr << "--init()--" << members.size() << std::endl; ) 250 if ( curMember != members.end() ) { 251 if ( auto field = curMember->as< ObjectDecl >() ) { 252 PRINT( std::cerr << "incremented to field: " << field << std::endl; ) 253 curType = field->get_type(); 254 memberIter.reset( createMemberIterator( location, curType ) ); 255 return true; 256 } 257 } 258 return false; 259 } 260 261 AggregateIterator( 262 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 263 const MemberList & ms ) 264 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 265 sub( genericSubstitution( i ) ) { 266 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) 267 init(); 268 } 269 270 public: 271 void setPosition( 272 std::deque< ptr< Expr > >::const_iterator begin, 273 std::deque< ptr< Expr > >::const_iterator end 274 ) final { 275 if ( begin == end ) return; 276 277 if ( auto varExpr = begin->as< VariableExpr >() ) { 278 for ( curMember = members.begin(); curMember != members.end(); ++curMember ) { 279 if ( *curMember != varExpr->var ) continue; 280 281 ++begin; 282 283 memberIter.reset( createMemberIterator( location, varExpr->result ) ); 284 curType = varExpr->result; 285 atbegin = curMember == members.begin() && begin == end; 286 memberIter->setPosition( begin, end ); 287 return; 288 } 289 assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 290 } else { 291 assertf( false, "1 bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() ); 292 } 293 } 294 295 std::deque< InitAlternative > operator* () const final { 296 if ( memberIter && *memberIter ) { 297 std::deque< InitAlternative > ret = memberIter->first(); 298 PRINT( std::cerr << "sub: " << sub << std::endl; ) 299 for ( InitAlternative & alt : ret ) { 300 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 301 alt.designation.get_and_mutate()->designators.emplace_front( 302 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 303 // need to substitute for generic types so that casts are to concrete types 304 alt.type = shallowCopy(alt.type.get()); 305 PRINT( std::cerr << " type is: " << alt.type; ) 306 sub.apply( alt.type ); // also apply to designation?? 307 PRINT( std::cerr << " ==> " << alt.type << std::endl; ) 308 } 309 return ret; 310 } 311 return {}; 312 } 313 314 AggregateIterator & smallStep() final { 315 PRINT( std::cerr << "smallStep in " << kind << std::endl; ) 316 atbegin = false; 317 if ( memberIter ) { 318 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; ) 319 memberIter->smallStep(); 320 if ( *memberIter ) { 321 PRINT( std::cerr << "success!" << std::endl; ) 322 return *this; 323 } 324 } 325 return bigStep(); 326 } 327 328 AggregateIterator & bigStep() override = 0; 329 330 const Type * getType() final { return inst; } 331 332 const Type * getNext() final { 333 bool hasMember = memberIter && *memberIter; 334 return hasMember ? memberIter->getType() : nullptr; 335 } 336 337 std::deque< InitAlternative > first() const final { 338 std::deque< InitAlternative > ret; 339 PRINT( std::cerr << "first " << kind << std::endl; ) 340 if ( memberIter && *memberIter ) { 341 PRINT( std::cerr << "adding children" << std::endl; ) 342 ret = memberIter->first(); 343 for ( InitAlternative & alt : ret ) { 344 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 345 alt.designation.get_and_mutate()->designators.emplace_front( 346 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 347 } 348 } 349 if ( atbegin ) { 350 // only add self if at the very beginning of the structure 351 PRINT( std::cerr << "adding self" << std::endl; ) 352 ret.emplace_front( inst, new Designation{ location } ); 43 44 /// Iterates members of a type by initializer. 45 class MemberIterator { 46 public: 47 virtual ~MemberIterator() {} 48 49 /// Internal set position based on iterator ranges. 50 virtual void setPosition( 51 std::deque< ptr< Expr > >::const_iterator it, 52 std::deque< ptr< Expr > >::const_iterator end ) = 0; 53 54 /// Walks the current object using the given designators as a guide. 55 void setPosition( const std::deque< ptr< Expr > > & designators ) { 56 setPosition( designators.begin(), designators.end() ); 57 } 58 59 /// Retrieve the list of possible (Type,Designation) pairs for the 60 /// current position in the current object. 61 virtual std::deque< InitAlternative > operator* () const = 0; 62 63 /// True if the iterator is not currently at the end. 64 virtual operator bool() const = 0; 65 66 /// Moves the iterator by one member in the current object. 67 virtual MemberIterator & bigStep() = 0; 68 69 /// Moves the iterator by one member in the current subobject. 70 virtual MemberIterator & smallStep() = 0; 71 72 /// The type of the current object. 73 virtual const Type * getType() = 0; 74 75 /// The type of the current subobject. 76 virtual const Type * getNext() = 0; 77 78 /// Helper for operator*; aggregates must add designator to each init 79 /// alternative, but adding designators in operator* creates duplicates. 80 virtual std::deque< InitAlternative > first() const = 0; 81 }; 82 83 namespace { 84 85 /// create a new MemberIterator that traverses a type correctly 86 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ); 87 88 /// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry 89 class SimpleIterator final : public MemberIterator { 90 CodeLocation location; 91 const Type * type = nullptr; 92 public: 93 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {} 94 95 void setPosition( 96 std::deque< ptr< Expr > >::const_iterator begin, 97 std::deque< ptr< Expr > >::const_iterator end 98 ) override { 99 if ( begin != end ) { 100 SemanticError( location, "Un-designated initializer given non-empty designator" ); 101 } 102 } 103 104 std::deque< InitAlternative > operator* () const override { return first(); } 105 106 operator bool() const override { return type; } 107 108 SimpleIterator & bigStep() override { return smallStep(); } 109 SimpleIterator & smallStep() override { 110 type = nullptr; // empty on increment because no members 111 return *this; 112 } 113 114 const Type * getType() override { return type; } 115 116 const Type * getNext() override { return type; } 117 118 std::deque< InitAlternative > first() const override { 119 if ( type ) return { InitAlternative{ type, new Designation{ location } } }; 120 return {}; 121 } 122 }; 123 124 /// Iterates over an indexed type: 125 class IndexIterator : public MemberIterator { 126 protected: 127 CodeLocation location; 128 size_t index = 0; 129 size_t size = 0; 130 std::unique_ptr<MemberIterator> memberIter; 131 public: 132 IndexIterator( const CodeLocation & loc, size_t size ) : 133 location( loc ), size( size ) 134 {} 135 136 void setPosition( const Expr * expr ) { 137 // need to permit integer-constant-expressions, including: integer constants, 138 // enumeration constants, character constants, sizeof expressions, alignof expressions, 139 // cast expressions 140 141 auto arg = eval( expr ); 142 assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" ); 143 index = arg.knownValue; 144 145 // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { 146 // try { 147 // index = constExpr->intValue(); 148 // } catch ( SemanticErrorException & ) { 149 // SemanticError( expr, "Constant expression of non-integral type in array designator: " ); 150 // } 151 // } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) { 152 // setPosition( castExpr->arg ); 153 // } else if ( dynamic_cast< const SizeofExpr * >( expr ) || dynamic_cast< const AlignofExpr * >( expr ) ) { 154 // index = 0; 155 // } else { 156 // assertf( false, "2 bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 157 // } 158 } 159 160 void setPosition( 161 std::deque<ast::ptr<ast::Expr>>::const_iterator begin, 162 std::deque<ast::ptr<ast::Expr>>::const_iterator end 163 ) override { 164 if ( begin == end ) return; 165 166 setPosition( *begin ); 167 memberIter->setPosition( ++begin, end ); 168 } 169 170 std::deque< InitAlternative > operator* () const override { return first(); } 171 172 operator bool() const override { return index < size; } 173 }; 174 175 /// Iterates over the members of array types: 176 class ArrayIterator final : public IndexIterator { 177 const ArrayType * array = nullptr; 178 const Type * base = nullptr; 179 180 size_t getSize( const Expr * expr ) { 181 auto res = eval( expr ); 182 if ( !res.hasKnownValue ) { 183 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) ); 184 } 185 return res.knownValue; 186 } 187 188 public: 189 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) : 190 IndexIterator( loc, getSize( at->dimension) ), 191 array( at ), base( at->base ) { 192 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) 193 memberIter.reset( createMemberIterator( loc, base ) ); 194 if ( at->isVarLen ) { 195 SemanticError( location, at, "VLA initialization does not support @=: " ); 196 } 197 } 198 199 ArrayIterator & bigStep() override { 200 PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 201 ++index; 202 memberIter.reset( index < size ? createMemberIterator( location, base ) : nullptr ); 203 return *this; 204 } 205 206 ArrayIterator & smallStep() override { 207 PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 208 if ( memberIter ) { 209 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; ) 210 memberIter->smallStep(); 211 if ( *memberIter ) { 212 PRINT( std::cerr << "has valid member iter" << std::endl; ) 213 return *this; 214 } 215 } 216 return bigStep(); 217 } 218 219 const Type * getType() override { return array; } 220 221 const Type * getNext() override { return base; } 222 223 std::deque< InitAlternative > first() const override { 224 PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 225 if ( memberIter && *memberIter ) { 226 std::deque< InitAlternative > ret = memberIter->first(); 227 for ( InitAlternative & alt : ret ) { 228 alt.designation.get_and_mutate()->designators.emplace_front( ConstantExpr::from_ulong( location, index ) ); 353 229 } 354 230 return ret; 355 231 } 356 }; 357 358 class StructIterator final : public AggregateIterator { 359 public: 360 StructIterator( const CodeLocation & loc, const StructInstType * inst ) 361 : AggregateIterator( loc, "StructIterator", inst->name, inst, inst->base->members ) {} 362 363 operator bool() const override { 364 return curMember != members.end() || (memberIter && *memberIter); 365 } 366 367 StructIterator & bigStep() override { 368 PRINT( std::cerr << "bigStep in " << kind << std::endl; ) 369 atbegin = false; 370 memberIter = nullptr; 371 curType = nullptr; 372 while ( curMember != members.end() ) { 373 ++curMember; 374 if ( init() ) return *this; 375 } 376 return *this; 377 } 378 }; 379 380 class UnionIterator final : public AggregateIterator { 381 public: 382 UnionIterator( const CodeLocation & loc, const UnionInstType * inst ) 383 : AggregateIterator( loc, "UnionIterator", inst->name, inst, inst->base->members ) {} 384 385 operator bool() const override { return memberIter && *memberIter; } 386 387 UnionIterator & bigStep() override { 388 // unions only initialize one member 389 PRINT( std::cerr << "bigStep in " << kind << std::endl; ) 390 atbegin = false; 391 memberIter = nullptr; 392 curType = nullptr; 393 curMember = members.end(); 394 return *this; 395 } 396 }; 397 398 /// Iterates across the positions in a tuple: 399 class TupleIterator final : public IndexIterator { 400 ast::TupleType const * const tuple; 401 402 const ast::Type * typeAtIndex() const { 403 assert( index < size ); 404 return tuple->types[ index ].get(); 405 } 406 407 public: 408 TupleIterator( const CodeLocation & loc, const TupleType * type ) 409 : IndexIterator( loc, type->size() ), tuple( type ) { 410 PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; ) 411 memberIter.reset( createMemberIterator( loc, typeAtIndex() ) ); 412 } 413 414 TupleIterator & bigStep() override { 415 ++index; 416 memberIter.reset( index < size ? 417 createMemberIterator( location, typeAtIndex() ) : nullptr ); 418 return *this; 419 } 420 421 TupleIterator & smallStep() override { 422 if ( memberIter ) { 423 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; ) 424 memberIter->smallStep(); 425 if ( !memberIter ) { 426 PRINT( std::cerr << "has valid member iter" << std::endl; ) 427 return *this; 428 } 429 } 430 return bigStep(); 431 } 432 433 const ast::Type * getType() override { 434 return tuple; 435 } 436 437 const ast::Type * getNext() override { 438 bool hasMember = memberIter && *memberIter; 439 return hasMember ? memberIter->getType() : nullptr; 440 } 441 442 std::deque< InitAlternative > first() const override { 443 PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; ) 444 if ( memberIter && *memberIter ) { 445 std::deque< InitAlternative > ret = memberIter->first(); 446 for ( InitAlternative & alt : ret ) { 447 alt.designation.get_and_mutate()->designators.emplace_front( 448 ConstantExpr::from_ulong( location, index ) ); 449 } 450 return ret; 451 } 452 return {}; 453 } 454 }; 455 456 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) { 457 if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) { 458 if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) { 459 assert( sit->base ); 460 return new StructIterator{ loc, sit }; 461 } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) { 462 assert( uit->base ); 463 return new UnionIterator{ loc, uit }; 464 } else { 465 assertf( 466 dynamic_cast< const EnumInstType * >( type ) 467 || dynamic_cast< const TypeInstType * >( type ), 468 "Encountered unhandled BaseInstType in createMemberIterator: %s", 469 toString( type ).c_str() ); 470 return new SimpleIterator{ loc, type }; 471 } 472 } else if ( auto at = dynamic_cast< const ArrayType * >( type ) ) { 473 return new ArrayIterator{ loc, at }; 474 } else if ( auto tt = dynamic_cast< const TupleType * >( type ) ) { 475 return new TupleIterator{ loc, tt }; 232 return {}; 233 } 234 }; 235 236 class AggregateIterator : public MemberIterator { 237 protected: 238 using MemberList = std::vector< ptr< Decl > >; 239 240 CodeLocation location; 241 std::string kind; // for debug 242 std::string name; 243 const Type * inst; 244 const MemberList & members; 245 MemberList::const_iterator curMember; 246 bool atbegin = true; // false at first {small,big}Step 247 const Type * curType = nullptr; 248 std::unique_ptr< MemberIterator > memberIter = nullptr; 249 TypeSubstitution sub; 250 251 bool init() { 252 PRINT( std::cerr << "--init()--" << members.size() << std::endl; ) 253 if ( curMember != members.end() ) { 254 if ( auto field = curMember->as< ObjectDecl >() ) { 255 PRINT( std::cerr << "incremented to field: " << field << std::endl; ) 256 curType = field->get_type(); 257 memberIter.reset( createMemberIterator( location, curType ) ); 258 return true; 259 } 260 } 261 return false; 262 } 263 264 AggregateIterator( 265 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 266 const MemberList & ms ) 267 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 268 sub( genericSubstitution( i ) ) { 269 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) 270 init(); 271 } 272 273 public: 274 void setPosition( 275 std::deque< ptr< Expr > >::const_iterator begin, 276 std::deque< ptr< Expr > >::const_iterator end 277 ) final { 278 if ( begin == end ) return; 279 280 if ( auto varExpr = begin->as< VariableExpr >() ) { 281 for ( curMember = members.begin(); curMember != members.end(); ++curMember ) { 282 if ( *curMember != varExpr->var ) continue; 283 284 ++begin; 285 286 memberIter.reset( createMemberIterator( location, varExpr->result ) ); 287 curType = varExpr->result; 288 atbegin = curMember == members.begin() && begin == end; 289 memberIter->setPosition( begin, end ); 290 return; 291 } 292 assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 476 293 } else { 294 assertf( false, "1 bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() ); 295 } 296 } 297 298 std::deque< InitAlternative > operator* () const final { 299 if ( memberIter && *memberIter ) { 300 std::deque< InitAlternative > ret = memberIter->first(); 301 PRINT( std::cerr << "sub: " << sub << std::endl; ) 302 for ( InitAlternative & alt : ret ) { 303 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 304 alt.designation.get_and_mutate()->designators.emplace_front( 305 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 306 // need to substitute for generic types so that casts are to concrete types 307 alt.type = shallowCopy(alt.type.get()); 308 PRINT( std::cerr << " type is: " << alt.type; ) 309 sub.apply( alt.type ); // also apply to designation?? 310 PRINT( std::cerr << " ==> " << alt.type << std::endl; ) 311 } 312 return ret; 313 } 314 return {}; 315 } 316 317 AggregateIterator & smallStep() final { 318 PRINT( std::cerr << "smallStep in " << kind << std::endl; ) 319 atbegin = false; 320 if ( memberIter ) { 321 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; ) 322 memberIter->smallStep(); 323 if ( *memberIter ) { 324 PRINT( std::cerr << "success!" << std::endl; ) 325 return *this; 326 } 327 } 328 return bigStep(); 329 } 330 331 AggregateIterator & bigStep() override = 0; 332 333 const Type * getType() final { return inst; } 334 335 const Type * getNext() final { 336 bool hasMember = memberIter && *memberIter; 337 return hasMember ? memberIter->getType() : nullptr; 338 } 339 340 std::deque< InitAlternative > first() const final { 341 std::deque< InitAlternative > ret; 342 PRINT( std::cerr << "first " << kind << std::endl; ) 343 if ( memberIter && *memberIter ) { 344 PRINT( std::cerr << "adding children" << std::endl; ) 345 ret = memberIter->first(); 346 for ( InitAlternative & alt : ret ) { 347 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 348 alt.designation.get_and_mutate()->designators.emplace_front( 349 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 350 } 351 } 352 if ( atbegin ) { 353 // only add self if at the very beginning of the structure 354 PRINT( std::cerr << "adding self" << std::endl; ) 355 ret.emplace_front( inst, new Designation{ location } ); 356 } 357 return ret; 358 } 359 }; 360 361 class StructIterator final : public AggregateIterator { 362 public: 363 StructIterator( const CodeLocation & loc, const StructInstType * inst ) 364 : AggregateIterator( loc, "StructIterator", inst->name, inst, inst->base->members ) {} 365 366 operator bool() const override { 367 return curMember != members.end() || (memberIter && *memberIter); 368 } 369 370 StructIterator & bigStep() override { 371 PRINT( std::cerr << "bigStep in " << kind << std::endl; ) 372 atbegin = false; 373 memberIter = nullptr; 374 curType = nullptr; 375 while ( curMember != members.end() ) { 376 ++curMember; 377 if ( init() ) return *this; 378 } 379 return *this; 380 } 381 }; 382 383 class UnionIterator final : public AggregateIterator { 384 public: 385 UnionIterator( const CodeLocation & loc, const UnionInstType * inst ) 386 : AggregateIterator( loc, "UnionIterator", inst->name, inst, inst->base->members ) {} 387 388 operator bool() const override { return memberIter && *memberIter; } 389 390 UnionIterator & bigStep() override { 391 // unions only initialize one member 392 PRINT( std::cerr << "bigStep in " << kind << std::endl; ) 393 atbegin = false; 394 memberIter = nullptr; 395 curType = nullptr; 396 curMember = members.end(); 397 return *this; 398 } 399 }; 400 401 /// Iterates across the positions in a tuple: 402 class TupleIterator final : public IndexIterator { 403 ast::TupleType const * const tuple; 404 405 const ast::Type * typeAtIndex() const { 406 assert( index < size ); 407 return tuple->types[ index ].get(); 408 } 409 410 public: 411 TupleIterator( const CodeLocation & loc, const TupleType * type ) 412 : IndexIterator( loc, type->size() ), tuple( type ) { 413 PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; ) 414 memberIter.reset( createMemberIterator( loc, typeAtIndex() ) ); 415 } 416 417 TupleIterator & bigStep() override { 418 ++index; 419 memberIter.reset( index < size ? 420 createMemberIterator( location, typeAtIndex() ) : nullptr ); 421 return *this; 422 } 423 424 TupleIterator & smallStep() override { 425 if ( memberIter ) { 426 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; ) 427 memberIter->smallStep(); 428 if ( !memberIter ) { 429 PRINT( std::cerr << "has valid member iter" << std::endl; ) 430 return *this; 431 } 432 } 433 return bigStep(); 434 } 435 436 const ast::Type * getType() override { 437 return tuple; 438 } 439 440 const ast::Type * getNext() override { 441 bool hasMember = memberIter && *memberIter; 442 return hasMember ? memberIter->getType() : nullptr; 443 } 444 445 std::deque< InitAlternative > first() const override { 446 PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; ) 447 if ( memberIter && *memberIter ) { 448 std::deque< InitAlternative > ret = memberIter->first(); 449 for ( InitAlternative & alt : ret ) { 450 alt.designation.get_and_mutate()->designators.emplace_front( 451 ConstantExpr::from_ulong( location, index ) ); 452 } 453 return ret; 454 } 455 return {}; 456 } 457 }; 458 459 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) { 460 if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) { 461 if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) { 462 assert( sit->base ); 463 return new StructIterator{ loc, sit }; 464 } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) { 465 assert( uit->base ); 466 return new UnionIterator{ loc, uit }; 467 } else { 468 assertf( 469 dynamic_cast< const EnumInstType * >( type ) 470 || dynamic_cast< const TypeInstType * >( type ), 471 "Encountered unhandled BaseInstType in createMemberIterator: %s", 472 toString( type ).c_str() ); 477 473 return new SimpleIterator{ loc, type }; 478 474 } 479 } 480 481 CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() { 482 objStack.emplace_back( new SimpleIterator{ loc, type } ); 483 } 484 485 const Designation * CurrentObject::findNext( const Designation * designation ) { 486 using DesignatorChain = std::deque< ptr< Expr > >; 487 PRINT( std::cerr << "___findNext" << std::endl; ) 488 489 // find all the d's 490 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts; 491 std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes; 492 for ( const Expr * expr : designation->designators ) { 493 PRINT( std::cerr << "____untyped: " << expr << std::endl; ) 494 auto dit = desigAlts.begin(); 495 496 for ( const Type * t : curTypes ) { 497 assert( dit != desigAlts.end() ); 498 DesignatorChain & d = *dit; 499 if ( auto nexpr = dynamic_cast< const NameExpr *>( expr ) ) { 500 PRINT( std::cerr << "____actual: " << t << std::endl; ) 501 if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) { 502 // concatenate identical field names 503 for ( const Decl * mem : refType->lookup( nexpr->name ) ) { 504 if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) { 505 PRINT( std::cerr << "____alt: " << field->type << std::endl; ) 506 DesignatorChain d2 = d; 507 d2.emplace_back( new VariableExpr{ expr->location, field } ); 508 newDesigAlts.emplace_back( std::move( d2 ) ); 509 newTypes.emplace_back( field->type ); 510 } 511 } 512 } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) { 513 auto nexpr = dynamic_cast< const NameExpr *>( expr ); 514 for ( const Decl * mem : refType->lookup( nexpr->name ) ) { 515 if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) { 516 DesignatorChain d2 = d; 517 d2.emplace_back( new VariableExpr{ expr->location, field } ); 518 newDesigAlts.emplace_back( std::move( d2 ) ); 519 newTypes.emplace_back( at->base ); 520 } 475 } else if ( auto at = dynamic_cast< const ArrayType * >( type ) ) { 476 return new ArrayIterator{ loc, at }; 477 } else if ( auto tt = dynamic_cast< const TupleType * >( type ) ) { 478 return new TupleIterator{ loc, tt }; 479 } else { 480 return new SimpleIterator{ loc, type }; 481 } 482 } 483 484 } // namespace 485 486 CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() { 487 objStack.emplace_back( new SimpleIterator{ loc, type } ); 488 } 489 490 const Designation * CurrentObject::findNext( const Designation * designation ) { 491 using DesignatorChain = std::deque< ptr< Expr > >; 492 PRINT( std::cerr << "___findNext" << std::endl; ) 493 494 // find all the d's 495 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts; 496 std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes; 497 for ( const Expr * expr : designation->designators ) { 498 PRINT( std::cerr << "____untyped: " << expr << std::endl; ) 499 auto dit = desigAlts.begin(); 500 501 for ( const Type * t : curTypes ) { 502 assert( dit != desigAlts.end() ); 503 DesignatorChain & d = *dit; 504 if ( auto nexpr = dynamic_cast< const NameExpr *>( expr ) ) { 505 PRINT( std::cerr << "____actual: " << t << std::endl; ) 506 if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) { 507 // concatenate identical field names 508 for ( const Decl * mem : refType->lookup( nexpr->name ) ) { 509 if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) { 510 PRINT( std::cerr << "____alt: " << field->type << std::endl; ) 511 DesignatorChain d2 = d; 512 d2.emplace_back( new VariableExpr{ expr->location, field } ); 513 newDesigAlts.emplace_back( std::move( d2 ) ); 514 newTypes.emplace_back( field->type ); 521 515 } 522 516 } 523 524 ++dit; 525 } else { 526 if ( auto at = dynamic_cast< const ArrayType * >( t ) ) { 527 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; ) 528 d.emplace_back( expr ); 529 newDesigAlts.emplace_back( d ); 530 newTypes.emplace_back( at->base ); 517 } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) { 518 auto nexpr = dynamic_cast< const NameExpr *>( expr ); 519 for ( const Decl * mem : refType->lookup( nexpr->name ) ) { 520 if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) { 521 DesignatorChain d2 = d; 522 d2.emplace_back( new VariableExpr{ expr->location, field } ); 523 newDesigAlts.emplace_back( std::move( d2 ) ); 524 newTypes.emplace_back( at->base ); 525 } 531 526 } 532 527 } 533 } 534 535 // reset queue 536 desigAlts = std::move( newDesigAlts ); 537 newDesigAlts.clear(); 538 curTypes = std::move( newTypes ); 539 newTypes.clear(); 540 assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() ); 541 } 542 543 if ( desigAlts.size() > 1 ) { 544 SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") ); 545 } else if ( desigAlts.empty() ) { 546 SemanticError( designation, "No reasonable alternatives for designation: " ); 547 } 548 549 DesignatorChain & d = desigAlts.back(); 550 PRINT( for ( Expression * expr : d ) { 551 std::cerr << "____desig: " << expr << std::endl; 552 } ) // for 553 assertf( ! curTypes.empty(), "empty designator chosen"); 554 555 // set new designators 556 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 557 Designation * actualDesignation = 558 new Designation{ designation->location, DesignatorChain{d} }; 559 objStack.back()->setPosition( d ); // destroys d 560 return actualDesignation; 561 } 562 563 void CurrentObject::setNext( const Designation * designation ) { 564 PRINT( std::cerr << "____setNext" << designation << std::endl; ) 565 assertf( ! objStack.empty(), "obj stack empty in setNext" ); 566 objStack.back()->setPosition( designation->designators ); 567 } 568 569 void CurrentObject::increment() { 570 PRINT( std::cerr << "____increment" << std::endl; ) 571 if ( objStack.empty() ) return; 528 529 ++dit; 530 } else { 531 if ( auto at = dynamic_cast< const ArrayType * >( t ) ) { 532 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; ) 533 d.emplace_back( expr ); 534 newDesigAlts.emplace_back( d ); 535 newTypes.emplace_back( at->base ); 536 } 537 } 538 } 539 540 // reset queue 541 desigAlts = std::move( newDesigAlts ); 542 newDesigAlts.clear(); 543 curTypes = std::move( newTypes ); 544 newTypes.clear(); 545 assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() ); 546 } 547 548 if ( desigAlts.size() > 1 ) { 549 SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") ); 550 } else if ( desigAlts.empty() ) { 551 SemanticError( designation, "No reasonable alternatives for designation: " ); 552 } 553 554 DesignatorChain & d = desigAlts.back(); 555 PRINT( for ( Expression * expr : d ) { 556 std::cerr << "____desig: " << expr << std::endl; 557 } ) // for 558 assertf( ! curTypes.empty(), "empty designator chosen"); 559 560 // set new designators 561 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 562 Designation * actualDesignation = 563 new Designation{ designation->location, DesignatorChain{d} }; 564 objStack.back()->setPosition( d ); // destroys d 565 return actualDesignation; 566 } 567 568 void CurrentObject::setNext( const Designation * designation ) { 569 PRINT( std::cerr << "____setNext" << designation << std::endl; ) 570 assertf( ! objStack.empty(), "obj stack empty in setNext" ); 571 objStack.back()->setPosition( designation->designators ); 572 } 573 574 void CurrentObject::increment() { 575 PRINT( std::cerr << "____increment" << std::endl; ) 576 if ( objStack.empty() ) return; 577 PRINT( std::cerr << *objStack.back() << std::endl; ) 578 objStack.back()->smallStep(); 579 } 580 581 void CurrentObject::enterListInit( const CodeLocation & loc ) { 582 PRINT( std::cerr << "____entering list init" << std::endl; ) 583 assertf( ! objStack.empty(), "empty obj stack entering list init" ); 584 const ast::Type * type = objStack.back()->getNext(); 585 assert( type ); 586 objStack.emplace_back( createMemberIterator( loc, type ) ); 587 } 588 589 void CurrentObject::exitListInit() { 590 PRINT( std::cerr << "____exiting list init" << std::endl; ) 591 assertf( ! objStack.empty(), "objstack empty" ); 592 objStack.pop_back(); 593 if ( ! objStack.empty() ) { 572 594 PRINT( std::cerr << *objStack.back() << std::endl; ) 573 objStack.back()->smallStep(); 574 } 575 576 void CurrentObject::enterListInit( const CodeLocation & loc ) { 577 PRINT( std::cerr << "____entering list init" << std::endl; ) 578 assertf( ! objStack.empty(), "empty obj stack entering list init" ); 579 const ast::Type * type = objStack.back()->getNext(); 580 assert( type ); 581 objStack.emplace_back( createMemberIterator( loc, type ) ); 582 } 583 584 void CurrentObject::exitListInit() { 585 PRINT( std::cerr << "____exiting list init" << std::endl; ) 586 assertf( ! objStack.empty(), "objstack empty" ); 587 objStack.pop_back(); 588 if ( ! objStack.empty() ) { 589 PRINT( std::cerr << *objStack.back() << std::endl; ) 590 objStack.back()->bigStep(); 591 } 592 } 593 594 std::deque< InitAlternative > CurrentObject::getOptions() { 595 PRINT( std::cerr << "____getting current options" << std::endl; ) 596 assertf( ! objStack.empty(), "objstack empty in getOptions" ); 597 return **objStack.back(); 598 } 599 600 const Type * CurrentObject::getCurrentType() { 601 PRINT( std::cerr << "____getting current type" << std::endl; ) 602 assertf( ! objStack.empty(), "objstack empty in getCurrentType" ); 603 return objStack.back()->getNext(); 604 } 605 } 595 objStack.back()->bigStep(); 596 } 597 } 598 599 std::deque< InitAlternative > CurrentObject::getOptions() { 600 PRINT( std::cerr << "____getting current options" << std::endl; ) 601 assertf( ! objStack.empty(), "objstack empty in getOptions" ); 602 return **objStack.back(); 603 } 604 605 const Type * CurrentObject::getCurrentType() { 606 PRINT( std::cerr << "____getting current type" << std::endl; ) 607 assertf( ! objStack.empty(), "objstack empty in getCurrentType" ); 608 return objStack.back()->getNext(); 609 } 610 611 } // namespace ast 606 612 607 613 // Local Variables: // -
src/ResolvExpr/CurrentObject.h
r16e0dcb rf7f997a 17 17 18 18 #include <deque> 19 #include <list> // for list20 19 #include <memory> // for unique_ptr 21 #include <stack> // for stack22 20 #include <vector> 23 21 … … 25 23 #include "Common/CodeLocation.h" 26 24 25 namespace ast { 26 27 // AST class types: 27 28 class Designation; 28 29 class Type; 29 30 struct InitAlternative; 30 31 31 namespace ResolvExpr { 32 32 /// Iterates members of a type by initializer 33 class MemberIterator; 33 34 34 // TODO: memory management of MemberIterators 35 class CurrentObject { 36 public: 37 CurrentObject(); 38 CurrentObject( Type * type ); 35 /// Builds initializer lists in resolution 36 class CurrentObject final { 37 std::vector<std::shared_ptr<MemberIterator>> objStack; 39 38 40 /// resolves unresolved designation 41 Designation * findNext( Designation * designation ); 42 /// sets current position using resolved designation 43 void setNext( Designation * designation ); 44 /// steps to next sub-object of current-object 45 void increment(); 46 /// sets new current-object for the duration of this brace-enclosed initializer-list 47 void enterListInit(); 48 /// restores previous current-object 49 void exitListInit(); 50 /// produces a list of alternatives (Type *, Designation *) for the current sub-object's initializer 51 std::list< InitAlternative > getOptions(); 52 /// produces the type of the current object but no subobjects 53 Type * getCurrentType(); 39 public: 40 CurrentObject() = default; 41 CurrentObject( const CodeLocation & loc, const Type * type ); 54 42 55 private: 56 std::stack< MemberIterator * > objStack; 57 }; 58 } // namespace ResolvExpr 43 /// Resolves unresolved designation. 44 const Designation * findNext( const Designation * designation ); 45 /// Sets current position using the resolved designation. 46 void setNext( const Designation * designation ); 47 /// Steps to next sub-object of current object. 48 void increment(); 49 /// Sets new current object for the duration of this brace-enclosed intializer-list. 50 void enterListInit( const CodeLocation & loc ); 51 /// Restores previous current object. 52 void exitListInit(); 53 /// Produces a list of alternatives (Type *, Designation *) 54 /// for the current sub-object's initializer. 55 std::deque< InitAlternative > getOptions(); 56 /// Produces the type of the current object but no subobjects. 57 const Type * getCurrentType(); 58 }; 59 59 60 namespace ast {61 // AST class types62 class Designation;63 struct InitAlternative;64 class Type;65 66 /// Iterates members of a type by initializer67 class MemberIterator;68 69 /// Builds initializer lists in resolution70 class CurrentObject final {71 std::vector< std::shared_ptr<MemberIterator> > objStack;72 73 public:74 CurrentObject() = default;75 CurrentObject( const CodeLocation & loc, const Type * type );76 77 /// resolves unresolved designation78 const Designation * findNext( const Designation * designation );79 /// sets current position using the resolved designation80 void setNext( const ast::Designation * designation );81 /// steps to next sub-object of current object82 void increment();83 /// sets new current object for the duration of this brace-enclosed intializer-list84 void enterListInit( const CodeLocation & loc );85 /// restores previous current object86 void exitListInit();87 /// produces a list of alternatives (Type *, Designation *) for the current sub-object's88 /// initializer.89 std::deque< InitAlternative > getOptions();90 /// produces the type of the current object but no subobjects91 const Type * getCurrentType();92 };93 60 } // namespace ast 94 61 -
src/ResolvExpr/FindOpenVars.cc
r16e0dcb rf7f997a 24 24 namespace ResolvExpr { 25 25 26 namespace { 27 struct FindOpenVars final : public ast::WithGuards { 28 ast::OpenVarSet & open; 29 ast::OpenVarSet & closed; 30 ast::AssertionSet & need; 31 ast::AssertionSet & have; 32 ast::TypeEnvironment & env; 33 bool nextIsOpen; 26 namespace { 34 27 35 FindOpenVars( 36 ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n, 37 ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen ) 38 : open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {} 28 struct FindOpenVars final : public ast::WithGuards { 29 ast::OpenVarSet & open; 30 ast::OpenVarSet & closed; 31 ast::AssertionSet & need; 32 ast::AssertionSet & have; 33 ast::TypeEnvironment & env; 34 bool nextIsOpen; 39 35 40 void previsit( const ast::FunctionType * type ) { 41 // mark open/closed variables 42 if ( nextIsOpen ) { 43 // trying to remove this from resolver. 44 // occasionally used in other parts so not deleting right now. 36 FindOpenVars( 37 ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n, 38 ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen ) 39 : open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {} 45 40 46 // insert open variables unbound to environment. 47 env.add(type->forall); 41 void previsit( const ast::FunctionType * type ) { 42 // mark open/closed variables 43 if ( nextIsOpen ) { 44 // trying to remove this from resolver. 45 // occasionally used in other parts so not deleting right now. 48 46 49 for ( auto & decl : type->forall ) { 50 open[ *decl ] = ast::TypeData{ decl->base }; 51 } 52 for ( auto & assert : type->assertions ) { 53 need[ assert ].isUsed = false; 54 } 55 } else { 56 for ( auto & decl : type->forall ) { 57 closed[ *decl ] = ast::TypeData{ decl->base }; 58 } 59 for ( auto & assert : type->assertions ) { 60 have[ assert ].isUsed = false; 61 } 62 } 47 // insert open variables unbound to environment. 48 env.add(type->forall); 63 49 64 // flip open variables for contained function types 65 nextIsOpen = ! nextIsOpen; 66 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } ); 50 for ( auto & decl : type->forall ) { 51 open[ *decl ] = ast::TypeData{ decl->base }; 67 52 } 53 for ( auto & assert : type->assertions ) { 54 need[ assert ].isUsed = false; 55 } 56 } else { 57 for ( auto & decl : type->forall ) { 58 closed[ *decl ] = ast::TypeData{ decl->base }; 59 } 60 for ( auto & assert : type->assertions ) { 61 have[ assert ].isUsed = false; 62 } 63 } 68 64 69 }; 65 // flip open variables for contained function types 66 // nextIsOpen = ! nextIsOpen; 67 // GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } ); 68 GuardValue( nextIsOpen ) = !nextIsOpen; 70 69 } 70 }; 71 71 72 void findOpenVars( 73 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 74 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) { 75 ast::Pass< FindOpenVars > finder{ open, closed, need, have, env, firstIsOpen }; 76 type->accept( finder ); 72 } // namespace 77 73 78 if (!closed.empty()) { 79 std::cerr << "closed: "; 80 for (auto& i : closed) { 81 std::cerr << i.first.base->location << ":" << i.first.base->name << ' '; 82 } 83 std::cerr << std::endl; 74 void findOpenVars( 75 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 76 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) { 77 ast::Pass< FindOpenVars > finder{ open, closed, need, have, env, firstIsOpen }; 78 type->accept( finder ); 79 80 if (!closed.empty()) { 81 std::cerr << "closed: "; 82 for (auto& i : closed) { 83 std::cerr << i.first.base->location << ":" << i.first.base->name << ' '; 84 84 } 85 std::cerr << std::endl; 85 86 } 87 } 88 86 89 } // namespace ResolvExpr 87 90 -
src/ResolvExpr/FindOpenVars.h
r16e0dcb rf7f997a 23 23 24 24 namespace ResolvExpr { 25 enum FirstMode { FirstClosed, FirstOpen };26 25 27 // Updates open and closed variables and their associated assertions 28 void findOpenVars( 29 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 30 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ); 26 enum FirstMode { FirstClosed, FirstOpen }; 27 28 // Updates open and closed variables and their associated assertions 29 void findOpenVars( 30 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 31 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ); 32 31 33 } // namespace ResolvExpr 32 34 -
src/ResolvExpr/PolyCost.cc
r16e0dcb rf7f997a 20 20 21 21 namespace ResolvExpr { 22 23 namespace { 22 24 23 25 class PolyCost { … … 45 47 }; 46 48 49 } // namespace 50 47 51 int polyCost( 48 52 const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env -
src/ResolvExpr/PtrsAssignable.cc
r16e0dcb rf7f997a 21 21 22 22 namespace ResolvExpr { 23 24 namespace { 23 25 24 26 struct PtrsAssignable : public ast::WithShortCircuiting { … … 51 53 } 52 54 }; 55 56 } // namespace 53 57 54 58 int ptrsAssignable( const ast::Type * src, const ast::Type * dst, -
src/ResolvExpr/RenameVars.h
r16e0dcb rf7f997a 21 21 22 22 namespace ResolvExpr { 23 enum RenameMode {24 GEN_USAGE, // for type in VariableExpr25 GEN_EXPR_ID // for type in decl26 };27 const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );28 23 29 /// resets internal state of renamer to avoid overflow 30 void resetTyVarRenaming(); 24 enum RenameMode { 25 GEN_USAGE, // for type in VariableExpr 26 GEN_EXPR_ID // for type in decl 27 }; 28 const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true ); 29 30 /// Resets internal state of renamer to avoid overflow. 31 void resetTyVarRenaming(); 32 31 33 } // namespace ResolvExpr 32 34 -
src/ResolvExpr/ResolvMode.h
r16e0dcb rf7f997a 17 17 18 18 namespace ResolvExpr { 19 /// Flag set for resolution20 struct ResolvMode {21 const bool adjust; ///< Adjust array and function types to pointer types? [false]22 const bool prune; ///< Prune alternatives to min-cost per return type? [true]23 const bool failFast; ///< Fail on no resulting alternatives? [true]24 19 25 constexpr ResolvMode(bool a, bool p, bool ff) 26 : adjust(a), prune(p), failFast(ff) {} 20 /// Flag set for resolution 21 struct ResolvMode { 22 const bool adjust; ///< Adjust array and function types to pointer types? [false] 23 const bool prune; ///< Prune alternatives to min-cost per return type? [true] 24 const bool failFast; ///< Fail on no resulting alternatives? [true] 27 25 28 /// Default settings 29 constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {} 30 31 /// With adjust flag set; turns array and function types into equivalent pointers 32 static constexpr ResolvMode withAdjustment() { return { true, true, true }; } 26 constexpr ResolvMode(bool a, bool p, bool ff) 27 : adjust(a), prune(p), failFast(ff) {} 33 28 34 /// With adjust flag set but prune unset; pruning ensures there is at least one alternative 35 /// per result type 36 static constexpr ResolvMode withoutPrune() { return { true, false, true }; } 29 /// Default settings 30 constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {} 37 31 38 /// With adjust and prune flags set but failFast unset; failFast ensures there is at least 39 /// one resulting alternative 40 static constexpr ResolvMode withoutFailFast() { return { true, true, false }; } 32 /// With adjust flag set; turns array and function types into equivalent pointers 33 static constexpr ResolvMode withAdjustment() { return { true, true, true }; } 41 34 42 /// The same mode, but with satisfyAssns turned on; for top-level calls 43 ResolvMode atTopLevel() const { return { adjust, true, failFast }; } 44 }; 35 /// With adjust flag set but prune unset; pruning ensures there is at least one alternative 36 /// per result type 37 static constexpr ResolvMode withoutPrune() { return { true, false, true }; } 38 39 /// With adjust and prune flags set but failFast unset; failFast ensures there is at least 40 /// one resulting alternative 41 static constexpr ResolvMode withoutFailFast() { return { true, true, false }; } 42 43 /// The same mode, but with satisfyAssns turned on; for top-level calls 44 ResolvMode atTopLevel() const { return { adjust, true, failFast }; } 45 }; 46 45 47 } // namespace ResolvExpr 46 48 -
src/ResolvExpr/ResolveTypeof.cc
r16e0dcb rf7f997a 33 33 34 34 namespace { 35 35 36 struct ResolveTypeof : public ast::WithShortCircuiting { 36 37 const ResolveContext & context; … … 75 76 } 76 77 }; 78 77 79 } // anonymous namespace 78 80 -
src/ResolvExpr/ResolveTypeof.h
r16e0dcb rf7f997a 22 22 23 23 namespace ResolvExpr { 24 struct ResolveContext;25 24 26 const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & ); 27 const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & ); 28 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & ); 29 const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & ); 25 struct ResolveContext; 26 27 const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & ); 28 const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & ); 29 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & ); 30 const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & ); 31 30 32 } // namespace ResolvExpr 31 33 -
src/ResolvExpr/Resolver.h
r16e0dcb rf7f997a 34 34 namespace ResolvExpr { 35 35 36 37 38 39 40 36 /// Helper Type: Passes around information between various sub-calls. 37 struct ResolveContext { 38 const ast::SymbolTable & symtab; 39 const ast::TranslationGlobal & global; 40 }; 41 41 42 /// Checks types and binds syntactic constructs to typed representations 43 void resolve( ast::TranslationUnit& translationUnit ); 44 /// Searches expr and returns the first DeletedExpr found, otherwise nullptr 45 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ); 46 /// Find the expression candidate that is the unique best match for `untyped` in a `void` 47 /// context. 48 ast::ptr< ast::Expr > resolveInVoidContext( 49 const ast::Expr * expr, const ResolveContext &, ast::TypeEnvironment & env ); 50 /// Resolve `untyped` to the single expression whose candidate is the best match for the 51 /// given type. 52 ast::ptr< ast::Expr > findSingleExpression( 53 const ast::Expr * untyped, const ast::Type * type, const ResolveContext & ); 54 ast::ptr< ast::Expr > findVoidExpression( 55 const ast::Expr * untyped, const ResolveContext & ); 56 /// Resolves a constructor init expression 57 ast::ptr< ast::Init > resolveCtorInit( 58 const ast::ConstructorInit * ctorInit, const ResolveContext & context ); 59 /// Resolves a statement expression 60 const ast::Expr * resolveStmtExpr( 61 const ast::StmtExpr * stmtExpr, const ResolveContext & context ); 42 /// Checks types and binds syntactic constructs to typed representations 43 void resolve( ast::TranslationUnit& translationUnit ); 44 /// Searches expr and returns the first DeletedExpr found, otherwise nullptr 45 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ); 46 /// Find the expression candidate that is the unique 47 /// best match for `untyped` in a `void` context. 48 ast::ptr< ast::Expr > resolveInVoidContext( 49 const ast::Expr * expr, const ResolveContext &, ast::TypeEnvironment & env ); 50 /// Resolve `untyped` to the single expression whose 51 /// candidate is the best match for the given type. 52 ast::ptr< ast::Expr > findSingleExpression( 53 const ast::Expr * untyped, const ast::Type * type, const ResolveContext & ); 54 ast::ptr< ast::Expr > findVoidExpression( 55 const ast::Expr * untyped, const ResolveContext & ); 56 /// Resolves a constructor init expression 57 ast::ptr< ast::Init > resolveCtorInit( 58 const ast::ConstructorInit * ctorInit, const ResolveContext & context ); 59 /// Resolves a statement expression 60 const ast::Expr * resolveStmtExpr( 61 const ast::StmtExpr * stmtExpr, const ResolveContext & context ); 62 62 63 } // namespace ResolvExpr 63 64 -
src/ResolvExpr/SatisfyAssertions.cpp
r16e0dcb rf7f997a 473 473 errors.emplace_back( ss.str() ); 474 474 goto nextSat; 475 } 476 else if ( result == AssertionResult::Skip ) { 475 } else if ( result == AssertionResult::Skip ) { 477 476 next.emplace_back(assn); 478 477 // goto nextSat; -
src/ResolvExpr/SpecCost.cc
r16e0dcb rf7f997a 33 33 } 34 34 35 36 37 35 /// The specialization counter inner class. 36 class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> { 37 int count = -1; ///< specialization count (-1 for none) 38 38 39 // Converts the max value to -1 (none), otherwise increments the value. 40 static int toNoneOrInc( int value ) { 41 assert( 0 <= value ); 42 return value < std::numeric_limits<int>::max() ? value + 1 : -1; 39 // Converts the max value to -1 (none), otherwise increments the value. 40 static int toNoneOrInc( int value ) { 41 assert( 0 <= value ); 42 return value < std::numeric_limits<int>::max() ? value + 1 : -1; 43 } 44 45 template<typename T> using MapperT = 46 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 47 48 // Update the minimum to the new lowest non-none value. 49 template<typename T> 50 void updateMinimumPresent( int & minimum, const T & list, MapperT<T> mapper ) { 51 for ( const auto & node : list ) { 52 count = -1; 53 54 if ( ast::Type const * type = mapper( node ) ) { 55 ast::Type const * newType = type->accept( *visitor ); 56 assert( newType == nullptr || newType == type ); 57 } 58 59 if ( count != -1 && count < minimum ) minimum = count; 43 60 } 61 } 44 62 45 template<typename T> using MapperT = 46 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 63 // Returns minimum non-negative count + 1 over type parameters (-1 if none such). 64 template<typename T> 65 int minimumPresent( const T & list, MapperT<T> mapper ) { 66 int minCount = std::numeric_limits<int>::max(); 67 updateMinimumPresent( minCount, list, mapper ); 68 return toNoneOrInc( minCount ); 69 } 47 70 48 // Update the minimum to the new lowest non-none value. 49 template<typename T> 50 void updateMinimumPresent( int & minimum, const T & list, MapperT<T> mapper ) { 51 for ( const auto & node : list ) { 52 count = -1; 71 public: 72 int result() const { return 0 <= count ? count : 0; } 53 73 54 if ( ast::Type const * type = mapper( node ) ) {55 ast::Type const * newType = type->accept( *visitor );56 assert( newType == nullptr || newType == type );57 74 // Mark specialization of base type. 75 void postvisit( const ast::PointerType * ) { if ( 0 <= count ) ++count; } 76 void postvisit( const ast::ArrayType * ) { if ( 0 <= count ) ++count; } 77 void postvisit( const ast::ReferenceType * ) { if ( 0 <= count ) ++count; } 58 78 59 if ( count != -1 && count < minimum ) minimum = count; 60 } 61 } 79 void postvisit( const ast::StructInstType * ) { if ( 0 <= count ) ++count; } 80 void postvisit( const ast::UnionInstType * ) { if ( 0 <= count ) ++count; } 62 81 63 // Returns minimum non-negative count + 1 over type parameters (-1 if none such). 64 template<typename T> 65 int minimumPresent( const T & list, MapperT<T> mapper ) { 66 int minCount = std::numeric_limits<int>::max(); 67 updateMinimumPresent( minCount, list, mapper ); 68 return toNoneOrInc( minCount ); 69 } 82 // Use the minimal specialization value over returns and params. 83 void previsit( const ast::FunctionType * fty ) { 84 int minCount = std::numeric_limits<int>::max(); 85 updateMinimumPresent( minCount, fty->params, type_deref ); 86 updateMinimumPresent( minCount, fty->returns, type_deref ); 87 // Add another level to minCount if set. 88 count = toNoneOrInc( minCount ); 89 // We have already visited children. 90 visit_children = false; 91 } 70 92 71 public: 72 int result() const { return 0 <= count ? count : 0; } 93 // Look for polymorphic parameters. 94 void previsit( const ast::StructInstType * sty ) { 95 count = minimumPresent( sty->params, expr_result ); 96 } 73 97 74 // Mark specialization of base type.75 void postvisit( const ast::PointerType * ) { if ( count >= 0 ) ++count; }76 void postvisit( const ast::ArrayType * ) { if ( count >= 0 ) ++count; }77 void postvisit( const ast::ReferenceType * ) { if ( count >= 0 ) ++count;}98 // Look for polymorphic parameters. 99 void previsit( const ast::UnionInstType * uty ) { 100 count = minimumPresent( uty->params, expr_result ); 101 } 78 102 79 void postvisit( const ast::StructInstType * ) { if ( count >= 0 ) ++count; } 80 void postvisit( const ast::UnionInstType * ) { if ( count >= 0 ) ++count; } 103 // Note polymorphic type (which may be specialized). 104 // xxx - maybe account for open/closed type variables 105 void postvisit( const ast::TypeInstType * ) { count = 0; } 81 106 82 // Use the minimal specialization value over returns and params. 83 void previsit( const ast::FunctionType * fty ) { 84 int minCount = std::numeric_limits<int>::max(); 85 updateMinimumPresent( minCount, fty->params, type_deref ); 86 updateMinimumPresent( minCount, fty->returns, type_deref ); 87 // Add another level to minCount if set. 88 count = toNoneOrInc( minCount ); 89 // We have already visited children. 90 visit_children = false; 91 } 92 93 // Look for polymorphic parameters. 94 void previsit( const ast::StructInstType * sty ) { 95 count = minimumPresent( sty->params, expr_result ); 96 } 97 98 // Look for polymorphic parameters. 99 void previsit( const ast::UnionInstType * uty ) { 100 count = minimumPresent( uty->params, expr_result ); 101 } 102 103 // Note polymorphic type (which may be specialized). 104 // xxx - maybe account for open/closed type variables 105 void postvisit( const ast::TypeInstType * ) { count = 0; } 106 107 // Use the minimal specialization over elements. 108 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize 109 void previsit( const ast::TupleType * tty ) { 110 count = minimumPresent( tty->types, type_deref ); 111 visit_children = false; 112 } 113 }; 107 // Use the minimal specialization over elements. 108 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize 109 void previsit( const ast::TupleType * tty ) { 110 count = minimumPresent( tty->types, type_deref ); 111 visit_children = false; 112 } 113 }; 114 114 115 115 } // namespace -
src/ResolvExpr/SpecCost.hpp
r16e0dcb rf7f997a 16 16 #pragma once 17 17 18 class Type;19 18 namespace ast { 20 19 class Type; … … 23 22 namespace ResolvExpr { 24 23 25 int specCost( Type * type );26 24 int specCost( const ast::Type * type ); 27 25 -
src/ResolvExpr/Unify.cc
r16e0dcb rf7f997a 537 537 // assert( open.find( *typeInst ) == open.end() ); 538 538 auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 ); 539 if ( otherInst && typeInst->name == otherInst->name)539 if ( otherInst && typeInst->name == otherInst->name ) { 540 540 this->result = otherInst; 541 // return otherInst;541 } 542 542 } 543 543 … … 628 628 result = dynamic_cast< const ast::OneType * >( type2 ); 629 629 } 630 631 private:632 template< typename RefType > void handleRefType( RefType *inst, Type *other );633 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );634 630 }; 635 631 -
src/ResolvExpr/Unify.h
r16e0dcb rf7f997a 15 15 16 16 #pragma once 17 18 #include <list> // for list19 17 20 18 #include "AST/Node.hpp" // for ptr … … 47 45 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, 48 46 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 49 const ast::OpenVarSet & open, WidenMode widen, 47 const ast::OpenVarSet & open, WidenMode widen, 50 48 ast::ptr<ast::Type> & common ); 51 49 52 50 bool typesCompatible( 53 const ast::Type *, const ast::Type *, 51 const ast::Type *, const ast::Type *, 54 52 const ast::TypeEnvironment & env = {} ); 55 53 -
src/ResolvExpr/WidenMode.h
r16e0dcb rf7f997a 17 17 18 18 namespace ResolvExpr { 19 struct WidenMode {20 WidenMode( bool first, bool second ): first( first ), second( second ) {}21 19 22 WidenMode &operator|=( const WidenMode &other ) { 23 first |= other.first; second |= other.second; return *this; 24 } 20 struct WidenMode { 21 WidenMode( bool first, bool second ): first( first ), second( second ) {} 25 22 26 WidenMode &operator&=( const WidenMode &other ) {27 first &= other.first; second &= other.second; return *this;28 23 WidenMode &operator|=( const WidenMode &other ) { 24 first |= other.first; second |= other.second; return *this; 25 } 29 26 30 WidenMode operator|( const WidenMode &other ) {31 WidenMode newWM( *this ); newWM |= other; return newWM;32 27 WidenMode &operator&=( const WidenMode &other ) { 28 first &= other.first; second &= other.second; return *this; 29 } 33 30 34 WidenMode operator&( const WidenMode &other ) {35 WidenMode newWM( *this ); newWM &= other; return newWM;36 31 WidenMode operator|( const WidenMode &other ) { 32 WidenMode newWM( *this ); newWM |= other; return newWM; 33 } 37 34 38 operator bool() { return first && second; } 35 WidenMode operator&( const WidenMode &other ) { 36 WidenMode newWM( *this ); newWM &= other; return newWM; 37 } 39 38 40 bool first : 1, second : 1; 41 }; 39 operator bool() { return first && second; } 42 40 43 static inline WidenMode noWiden() { return { false, false }; } 41 bool first : 1, second : 1; 42 }; 43 44 static inline WidenMode noWiden() { return { false, false }; } 45 44 46 } // namespace ResolvExpr 45 47 -
tests/exceptions/.expect/cardgame.x86.txt
r16e0dcb rf7f997a 1 1 start 2 203 374 235 76 2 1 7 1158 1159 3 0 10 62 11 8 12 41 13 4294967295 4 1 5 2 6 1 7 3 8 1 9 1 14 10 0 15 92 16 134 17 8 18 67 19 23 20 27 21 138 22 133 11 2 12 1 13 5 14 0 23 15 4 24 59 25 79 26 122 27 23 28 5 16 0 29 17 2 30 33 31 15 32 106 18 1 33 19 0 34 1435 9036 429496729537 8138 3939 429496729540 3641 11642 16043 7644 12745 446 2947 648 1249 950 1851 20 3 52 21 done
Note: See TracChangeset
for help on using the changeset viewer.