Ignore:
Timestamp:
Nov 17, 2023, 3:23:48 PM (2 years ago)
Author:
caparson <caparson@…>
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.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/CommonType.cc

    r16e0dcb rf7f997a  
    343343        );
    344344
    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 };
     345class 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;
     352public:
     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 };
    377398                                }
     399                        }
     400                }
     401        }
     402
     403private:
     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
     433public:
     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 );
    378442                        } 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 )
    381446                        ) {
    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
    391478                                        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;
    398639                                        }
    399640                                }
    400641                        }
    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 );
    610694                        } 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 that
    637                                         // ref{,2}->base are unchanged
    638                                         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 qualifiers
    647                                                         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 ) ) {
    693695                                if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
    694696                                        result = type2;
    695697                                        add_qualifiers( result, zero->qualifiers );
    696698                                }
    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 {
    717719                                if ( widen.second || one->qualifiers <= type2->qualifiers ) {
    718720                                        result = type2;
    719721                                        add_qualifiers( result, one->qualifiers );
    720722                                }
    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
     730namespace {
     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 ) ) {
    754747                                PRINT(
    755                                         std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
     748                                        std::cerr << "widen okay" << std::endl;
    756749                                )
    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
     762ast::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
    766788                        PRINT(
    767                                 std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
     789                                std::cerr << "formal is reference; result should be reference" << std::endl;
    768790                        )
    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}
    818807
    819808} // namespace ResolvExpr
Note: See TracChangeset for help on using the changeset viewer.