Changeset c6b4432 for src/ResolvExpr/CommonType.cc
- Timestamp:
- Nov 8, 2023, 2:01:11 PM (10 months ago)
- Branches:
- master
- Children:
- 3e4bf0d, f5ec35a
- Parents:
- 790d835
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CommonType.cc
r790d835 rc6b4432 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 … … 488 342 "Each basic type kind should have a corresponding row in the combined type matrix" 489 343 ); 490 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 } // if503 } else if ( dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {504 // use signed int in lieu of the enum/zero/one type505 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 } // if509 } 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 } // if518 }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 } // if558 strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2;559 } else {560 /// std::cerr << "place for ptr-to-type" << std::endl;561 } // if562 pointerType->get_base()->tq = tq1;563 otherPointer->get_base()->tq = tq2;564 } // if565 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {566 result = pointerType->clone();567 result->tq |= type2->tq;568 } // if569 }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 } // if595 strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2;596 } else {597 /// std::cerr << "place for ptr-to-type" << std::endl;598 } // if599 refType->get_base()->tq = tq1;600 otherRef->get_base()->tq = tq2;601 } // if602 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {603 result = refType->clone();604 result->tq |= type2->tq;605 } // if606 }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 enumInstType615 result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );616 } // if617 }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 } // if637 type2->tq = tq2;638 type->get_base()->tq = Type::Qualifiers();639 } // if640 } // if641 } // if642 }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 344 675 345 class CommonType_new final : public ast::WithShortCircuiting {
Note: See TracChangeset
for help on using the changeset viewer.