Changeset f7f997a for src/ResolvExpr/CommonType.cc
- Timestamp:
- Nov 17, 2023, 3:23:48 PM (2 years ago)
- Branches:
- master
- Children:
- decd4a6
- Parents:
- 16e0dcb (diff), 2908f08 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - File:
-
- 1 edited
-
src/ResolvExpr/CommonType.cc (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
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
Note:
See TracChangeset
for help on using the changeset viewer.