Changeset 8d182b1 for src/ResolvExpr/CommonType.cc
- Timestamp:
- Nov 14, 2023, 12:19:09 PM (23 months ago)
- Branches:
- master
- Children:
- 1ccae59, 89a8bab
- Parents:
- df8ba61a (diff), 5625427 (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
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CommonType.cc
rdf8ba61a r8d182b1 23 23 #include "AST/Pass.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h"26 #include "ResolvExpr/TypeEnvironment.h" // for OpenVarSet, AssertionSet27 #include "SymTab/Indexer.h" // for Indexer28 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl (ptr...29 #include "SynTree/Type.h" // for BasicType, BasicType::Kind::...30 #include "SynTree/Visitor.h" // for Visitor31 25 #include "Unify.h" // for unifyExact, WidenMode 32 26 #include "typeops.h" // for isFtype … … 41 35 42 36 namespace ResolvExpr { 43 struct CommonType_old : public WithShortCircuiting {44 CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );45 Type * get_result() const { return result; }46 47 void previsit( BaseSyntaxNode * ) { visit_children = false; }48 49 void postvisit( VoidType * voidType );50 void postvisit( BasicType * basicType );51 void postvisit( PointerType * pointerType );52 void postvisit( ArrayType * arrayType );53 void postvisit( ReferenceType * refType );54 void postvisit( FunctionType * functionType );55 void postvisit( StructInstType * aggregateUseType );56 void postvisit( UnionInstType * aggregateUseType );57 void postvisit( EnumInstType * aggregateUseType );58 void postvisit( TraitInstType * aggregateUseType );59 void postvisit( TypeInstType * aggregateUseType );60 void postvisit( TupleType * tupleType );61 void postvisit( VarArgsType * varArgsType );62 void postvisit( ZeroType * zeroType );63 void postvisit( OneType * oneType );64 65 private:66 template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer );67 template< typename RefType > void handleRefType( RefType * inst, Type * other );68 69 Type * result;70 Type * type2; // inherited71 bool widenFirst, widenSecond;72 const SymTab::Indexer &indexer;73 TypeEnvironment &env;74 const OpenVarSet &openVars;75 };76 77 Type * handleReference( Type * t1, Type * t2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {78 Type * common = nullptr;79 AssertionSet have, need;80 OpenVarSet newOpen( openVars );81 // need unify to bind type variables82 if ( unify( t1, t2, env, have, need, newOpen, indexer, common ) ) {83 PRINT(84 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;85 )86 if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) {87 PRINT(88 std::cerr << "widen okay" << std::endl;89 )90 common->tq |= t1->tq;91 common->tq |= t2->tq;92 return common;93 }94 }95 PRINT(96 std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;97 )98 return nullptr;99 }100 101 Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {102 PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );103 104 int depth1 = type1->referenceDepth();105 int depth2 = type2->referenceDepth();106 if ( depth1 > 0 || depth2 > 0 ) {107 int diff = depth1-depth2;108 // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed.109 // if ( diff > 1 || diff < -1 ) return nullptr;110 111 // special case where one type has a reference depth of 1 larger than the other112 if ( diff > 0 || diff < 0 ) {113 PRINT(114 std::cerr << "reference depth diff: " << diff << std::endl;115 )116 Type * result = nullptr;117 ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 );118 ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 );119 if ( diff > 0 ) {120 // deeper on the left121 assert( ref1 );122 result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );123 } else {124 // deeper on the right125 assert( ref2 );126 result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );127 }128 if ( result && ref1 ) {129 // formal is reference, so result should be reference130 PRINT(131 std::cerr << "formal is reference; result should be reference" << std::endl;132 )133 result = new ReferenceType( ref1->tq, result );134 }135 PRINT(136 std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl;137 )138 return result;139 }140 // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor.141 }142 143 type1->accept( visitor );144 Type * result = visitor.pass.get_result();145 if ( ! result ) {146 // this appears to be handling for opaque type declarations147 if ( widenSecond ) {148 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) {149 if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) {150 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );151 if ( type->get_base() ) {152 Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq;153 AssertionSet have, need;154 OpenVarSet newOpen( openVars );155 type1->tq = Type::Qualifiers();156 type->get_base()->tq = tq1;157 if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) {158 result = type1->clone();159 result->tq = tq1 | tq2;160 } // if161 type1->tq = tq1;162 type->get_base()->tq = Type::Qualifiers();163 } // if164 } // if165 } // if166 } // if167 } // if168 #ifdef DEBUG169 std::cerr << "============= commonType" << std::endl << "type1 is ";170 type1->print( std::cerr );171 std::cerr << " type2 is ";172 type2->print( std::cerr );173 if ( result ) {174 std::cerr << " common type is ";175 result->print( std::cerr );176 } else {177 std::cerr << " no common type";178 } // if179 std::cerr << std::endl;180 #endif181 return result;182 }183 37 184 38 // GENERATED START, DO NOT EDIT … … 489 343 ); 490 344 491 CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) 492 : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) { 493 } 494 495 void CommonType_old::postvisit( VoidType * ) {} 496 497 void CommonType_old::postvisit( BasicType * basicType ) { 498 if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) { 499 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ (ast::BasicType::Kind)(int)otherBasic->get_kind() ]; 500 if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) { 501 result = new BasicType( basicType->tq | otherBasic->tq, newType ); 502 } // if 503 } else if ( dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) { 504 // use signed int in lieu of the enum/zero/one type 505 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ ast::BasicType::SignedInt ]; 506 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) { 507 result = new BasicType( basicType->tq | type2->tq, newType ); 508 } // if 509 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) { 510 const EnumDecl* enumDecl = enumInst->baseEnum; 511 if ( const Type* baseType = enumDecl->base ) { 512 result = baseType->clone(); 513 } else { 514 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ ast::BasicType::SignedInt ]; 515 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) { 516 result = new BasicType( basicType->tq | type2->tq, newType ); 517 } // if 518 } 519 } 520 } 521 522 template< typename Pointer > 523 void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) { 524 if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) { 525 OpenVarSet::const_iterator entry = openVars.find( var->get_name() ); 526 if ( entry != openVars.end() ) { 527 AssertionSet need, have; 528 WidenMode widen( widenFirst, widenSecond ); 529 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return; 530 } 531 } 532 result = voidPointer->clone(); 533 result->tq |= otherPointer->tq; 534 } 535 536 void CommonType_old::postvisit( PointerType * pointerType ) { 537 if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) { 538 // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl; 539 if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) { 540 getCommonWithVoidPointer( otherPointer, pointerType ); 541 } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) { 542 getCommonWithVoidPointer( pointerType, otherPointer ); 543 } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst ) 544 && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) { 545 // std::cerr << "middle case" << std::endl; 546 Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq; 547 pointerType->get_base()->tq = Type::Qualifiers(); 548 otherPointer->get_base()->tq = Type::Qualifiers(); 549 AssertionSet have, need; 550 OpenVarSet newOpen( openVars ); 551 if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) { 552 // std::cerr << "unifyExact success" << std::endl; 553 if ( tq1 < tq2 ) { 554 result = pointerType->clone(); 555 } else { 556 result = otherPointer->clone(); 557 } // if 558 strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2; 559 } else { 560 /// std::cerr << "place for ptr-to-type" << std::endl; 561 } // if 562 pointerType->get_base()->tq = tq1; 563 otherPointer->get_base()->tq = tq2; 564 } // if 565 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 566 result = pointerType->clone(); 567 result->tq |= type2->tq; 568 } // if 569 } 570 571 void CommonType_old::postvisit( ArrayType * ) {} 572 573 void CommonType_old::postvisit( ReferenceType * refType ) { 574 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) { 575 // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl; 576 // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl; 577 if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) { 578 getCommonWithVoidPointer( otherRef, refType ); 579 } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) { 580 getCommonWithVoidPointer( refType, otherRef ); 581 } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) 582 && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) { 583 // std::cerr << "middle case" << std::endl; 584 Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq; 585 refType->get_base()->tq = Type::Qualifiers(); 586 otherRef->get_base()->tq = Type::Qualifiers(); 587 AssertionSet have, need; 588 OpenVarSet newOpen( openVars ); 589 if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) { 590 if ( tq1 < tq2 ) { 591 result = refType->clone(); 592 } else { 593 result = otherRef->clone(); 594 } // if 595 strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2; 596 } else { 597 /// std::cerr << "place for ptr-to-type" << std::endl; 598 } // if 599 refType->get_base()->tq = tq1; 600 otherRef->get_base()->tq = tq2; 601 } // if 602 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 603 result = refType->clone(); 604 result->tq |= type2->tq; 605 } // if 606 } 607 608 void CommonType_old::postvisit( FunctionType * ) {} 609 void CommonType_old::postvisit( StructInstType * ) {} 610 void CommonType_old::postvisit( UnionInstType * ) {} 611 612 void CommonType_old::postvisit( EnumInstType * enumInstType ) { 613 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) { 614 // reuse BasicType, EnumInstType code by swapping type2 with enumInstType 615 result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars ); 616 } // if 617 } 618 619 void CommonType_old::postvisit( TraitInstType * ) { 620 } 621 622 void CommonType_old::postvisit( TypeInstType * inst ) { 623 if ( widenFirst ) { 624 const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ); 625 if ( nt ) { 626 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt ); 627 if ( type->get_base() ) { 628 Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq; 629 AssertionSet have, need; 630 OpenVarSet newOpen( openVars ); 631 type2->tq = Type::Qualifiers(); 632 type->get_base()->tq = tq1; 633 if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) { 634 result = type2->clone(); 635 result->tq = tq1 | tq2; 636 } // if 637 type2->tq = tq2; 638 type->get_base()->tq = Type::Qualifiers(); 639 } // if 640 } // if 641 } // if 642 } 643 644 void CommonType_old::postvisit( TupleType * ) {} 645 void CommonType_old::postvisit( VarArgsType * ) {} 646 647 void CommonType_old::postvisit( ZeroType * zeroType ) { 648 if ( widenFirst ) { 649 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) { 650 if ( widenSecond || zeroType->tq <= type2->tq ) { 651 result = type2->clone(); 652 result->tq |= zeroType->tq; 653 } 654 } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) { 655 result = new BasicType( zeroType->tq, BasicType::SignedInt ); 656 result->tq |= type2->tq; 657 } 658 } 659 } 660 661 void CommonType_old::postvisit( OneType * oneType ) { 662 if ( widenFirst ) { 663 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) { 664 if ( widenSecond || oneType->tq <= type2->tq ) { 665 result = type2->clone(); 666 result->tq |= oneType->tq; 667 } 668 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 669 result = new BasicType( oneType->tq, BasicType::SignedInt ); 670 result->tq |= type2->tq; 671 } 672 } 673 } 674 675 class CommonType_new final : public ast::WithShortCircuiting { 345 class CommonType final : public ast::WithShortCircuiting { 676 346 const ast::Type * type2; 677 347 WidenMode widen; … … 684 354 ast::ptr< ast::Type > result; 685 355 686 CommonType _new(356 CommonType( 687 357 const ast::Type * t2, WidenMode w, 688 358 ast::TypeEnvironment & env, const ast::OpenVarSet & o, … … 718 388 result = enumDecl->base.get(); 719 389 } else { 720 #warning remove casts when `commonTypes` moved to new AST721 390 ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ]; 722 391 if ( … … 1069 738 }; 1070 739 1071 // size_t CommonType _new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");740 // size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType"); 1072 741 namespace { 1073 742 ast::ptr< ast::Type > handleReference( … … 1141 810 } 1142 811 // otherwise both are reference types of the same depth and this is handled by the visitor 1143 ast::Pass<CommonType _new> visitor{ type2, widen, env, open, need, have };812 ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have }; 1144 813 type1->accept( visitor ); 1145 814 // ast::ptr< ast::Type > result = visitor.core.result;
Note:
See TracChangeset
for help on using the changeset viewer.