Changeset f7f997a


Ignore:
Timestamp:
Nov 17, 2023, 3:23:48 PM (6 months 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

Files:
22 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/AdjustExprType.cc

    r16e0dcb rf7f997a  
    2323
    2424namespace {
    25         class AdjustExprType final : public ast::WithShortCircuiting {
    26                 const ast::SymbolTable & symtab;
    27         public:
    28                 const ast::TypeEnvironment & tenv;
    2925
    30                 AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    31                 : symtab( syms ), tenv( e ) {}
     26class AdjustExprType final : public ast::WithShortCircuiting {
     27        const ast::SymbolTable & symtab;
     28public:
     29        const ast::TypeEnvironment & tenv;
    3230
    33                 void previsit( const ast::VoidType * ) { visit_children = false; }
    34                 void previsit( const ast::BasicType * ) { visit_children = false; }
    35                 void previsit( const ast::PointerType * ) { visit_children = false; }
    36                 void previsit( const ast::ArrayType * ) { visit_children = false; }
    37                 void previsit( const ast::FunctionType * ) { visit_children = false; }
    38                 void previsit( const ast::StructInstType * ) { visit_children = false; }
    39                 void previsit( const ast::UnionInstType * ) { visit_children = false; }
    40                 void previsit( const ast::EnumInstType * ) { visit_children = false; }
    41                 void previsit( const ast::TraitInstType * ) { visit_children = false; }
    42                 void previsit( const ast::TypeInstType * ) { visit_children = false; }
    43                 void previsit( const ast::TupleType * ) { visit_children = false; }
    44                 void previsit( const ast::VarArgsType * ) { visit_children = false; }
    45                 void previsit( const ast::ZeroType * ) { visit_children = false; }
    46                 void previsit( const ast::OneType * ) { visit_children = false; }
     31        AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
     32        : symtab( syms ), tenv( e ) {}
    4733
    48                 const ast::Type * postvisit( const ast::ArrayType * at ) {
    49                         return new ast::PointerType{ at->base, at->qualifiers };
    50                 }
     34        void previsit( const ast::VoidType * ) { visit_children = false; }
     35        void previsit( const ast::BasicType * ) { visit_children = false; }
     36        void previsit( const ast::PointerType * ) { visit_children = false; }
     37        void previsit( const ast::ArrayType * ) { visit_children = false; }
     38        void previsit( const ast::FunctionType * ) { visit_children = false; }
     39        void previsit( const ast::StructInstType * ) { visit_children = false; }
     40        void previsit( const ast::UnionInstType * ) { visit_children = false; }
     41        void previsit( const ast::EnumInstType * ) { visit_children = false; }
     42        void previsit( const ast::TraitInstType * ) { visit_children = false; }
     43        void previsit( const ast::TypeInstType * ) { visit_children = false; }
     44        void previsit( const ast::TupleType * ) { visit_children = false; }
     45        void previsit( const ast::VarArgsType * ) { visit_children = false; }
     46        void previsit( const ast::ZeroType * ) { visit_children = false; }
     47        void previsit( const ast::OneType * ) { visit_children = false; }
    5148
    52                 const ast::Type * postvisit( const ast::FunctionType * ft ) {
    53                         return new ast::PointerType{ ft };
    54                 }
     49        const ast::Type * postvisit( const ast::ArrayType * at ) {
     50                return new ast::PointerType( at->base, at->qualifiers );
     51        }
    5552
    56                 const ast::Type * postvisit( const ast::TypeInstType * inst ) {
    57                         // replace known function-type-variables with pointer-to-function
    58                         if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
    59                                 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
    60                                         return new ast::PointerType{ inst };
    61                                 }
    62                         } else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) {
    63                                 if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) {
    64                                         if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
    65                                                 return new ast::PointerType{ inst };
    66                                         }
     53        const ast::Type * postvisit( const ast::FunctionType * ft ) {
     54                return new ast::PointerType( ft );
     55        }
     56
     57        const ast::Type * postvisit( const ast::TypeInstType * inst ) {
     58                // replace known function-type-variables with pointer-to-function
     59                if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
     60                        if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
     61                                return new ast::PointerType( inst );
     62                        }
     63                } else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) {
     64                        if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) {
     65                                if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
     66                                        return new ast::PointerType( inst );
    6767                                }
    6868                        }
    69                         return inst;
    7069                }
    71         };
     70                return inst;
     71        }
     72};
     73
    7274} // anonymous namespace
    7375
  • src/ResolvExpr/CandidateFinder.cpp

    r16e0dcb rf7f997a  
    751751                        const ast::Type * returnType = funcType->returns.front();
    752752                        if ( selfFinder.strictMode ) {
    753                                 if ( ! unifyExact(
     753                                if ( !unifyExact(
    754754                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden() ) // xxx - is no widening correct?
    755755                                ) {
     
    757757                                        return;
    758758                                }
    759                         }
    760                         else {
    761                                 if ( ! unify(
     759                        } else {
     760                                if ( !unify(
    762761                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen )
    763762                                ) {
     
    11091108                                                intrinsicResult.emplace_back(std::move(withFunc));
    11101109                                        }
    1111                                 }
    1112                                 else {
     1110                                } else {
    11131111                                        candidates.emplace_back( std::move( withFunc ) );
    11141112                                }
     
    11561154
    11571155                for ( CandidateRef & r : finder.candidates ) {
    1158                         if ( ! isLvalue( r->expr ) ) continue;
     1156                        if ( !isLvalue( r->expr ) ) continue;
    11591157                        addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
    11601158                }
  • 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
  • src/ResolvExpr/Cost.h

    r16e0dcb rf7f997a  
    2121
    2222namespace ResolvExpr {
    23         // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the
    24         // specialization cost is a negative value so a correction is needed is a few places.
    2523
    26         class Cost {
    27                 union {
    28                         struct {
    29                         #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    30                                 // Little-endian => first value is low priority and last is high priority.
    31                                 unsigned char padding;                                  ///< unused
    32                                 unsigned char referenceCost;                    ///< reference conversions
    33                                 unsigned char specCost;                                 ///< Polymorphic type specializations (type assertions), negative cost
    34                                 unsigned char varCost;                                  ///< Count of polymorphic type variables
    35                                 unsigned char signCost;                                 ///< Count of safe sign conversions
    36                                 unsigned char safeCost;                                 ///< Safe (widening) conversions
    37                                 unsigned char polyCost;                                 ///< Count of parameters and return values bound to some poly type
    38                                 unsigned char unsafeCost;                               ///< Unsafe (narrowing) conversions
    39                         #else
    40                                 #error Cost BIG_ENDIAN unsupported
    41                         #endif
    42                         } v;
    43                         uint64_t all;
     24// To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the
     25// specialization cost is a negative value so a correction is needed is a few places.
     26
     27class Cost {
     28        union {
     29                struct {
     30                #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     31                        // Little-endian => first value is low priority and last is high priority.
     32                        unsigned char padding;                                  ///< unused
     33                        unsigned char referenceCost;                    ///< reference conversions
     34                        unsigned char specCost;                                 ///< Polymorphic type specializations (type assertions), negative cost
     35                        unsigned char varCost;                                  ///< Count of polymorphic type variables
     36                        unsigned char signCost;                                 ///< Count of safe sign conversions
     37                        unsigned char safeCost;                                 ///< Safe (widening) conversions
     38                        unsigned char polyCost;                                 ///< Count of parameters and return values bound to some poly type
     39                        unsigned char unsafeCost;                               ///< Unsafe (narrowing) conversions
     40                #else
     41                        #error Cost BIG_ENDIAN unsupported
     42                #endif
     43                } v;
     44                uint64_t all;
     45        };
     46        static const unsigned char correctb = 0xff;             // byte correction for negative spec cost
     47        static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost
     48  public:
     49        // Compiler adjusts constants for correct endian.
     50        enum : uint64_t {
     51                zero      = 0x00'00'00'00'00'ff'00'00,
     52                infinity  = 0xff'ff'ff'ff'ff'00'ff'ff,
     53                unsafe    = 0x01'00'00'00'00'ff'00'00,
     54                poly      = 0x00'01'00'00'00'ff'00'00,
     55                safe      = 0x00'00'01'00'00'ff'00'00,
     56                sign      = 0x00'00'00'01'00'ff'00'00,
     57                var       = 0x00'00'00'00'01'ff'00'00,
     58                spec      = 0x00'00'00'00'00'fe'00'00,
     59                reference = 0x00'00'00'00'00'ff'01'00,
     60        }; //'
     61
     62        Cost( uint64_t all ) { Cost::all = all; }
     63        Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) {
     64                // Assume little-endian => first value is low priority and last is high priority.
     65                v = {
     66                #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     67                        (unsigned char)0,                                               // padding
     68                        (unsigned char)referenceCost,                   // low priority
     69                        (unsigned char)(specCost + correctb),   // correct for signedness
     70                        (unsigned char)varCost,
     71                        (unsigned char)signCost,
     72                        (unsigned char)safeCost,
     73                        (unsigned char)polyCost,
     74                        (unsigned char)unsafeCost,                              // high priority
     75                #else
     76                        #error Cost BIG_ENDIAN unsupported
     77                #endif
    4478                };
    45                 static const unsigned char correctb = 0xff;             // byte correction for negative spec cost
    46                 static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost
    47           public:
    48                 // Compiler adjusts constants for correct endian.
    49                 enum : uint64_t {
    50                         zero      = 0x00'00'00'00'00'ff'00'00,
    51                         infinity  = 0xff'ff'ff'ff'ff'00'ff'ff,
    52                         unsafe    = 0x01'00'00'00'00'ff'00'00,
    53                         poly      = 0x00'01'00'00'00'ff'00'00,
    54                         safe      = 0x00'00'01'00'00'ff'00'00,
    55                         sign      = 0x00'00'00'01'00'ff'00'00,
    56                         var       = 0x00'00'00'00'01'ff'00'00,
    57                         spec      = 0x00'00'00'00'00'fe'00'00,
    58                         reference = 0x00'00'00'00'00'ff'01'00,
    59                 }; //'
     79        }
    6080
    61                 Cost( uint64_t all ) { Cost::all = all; }
    62                 Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) {
    63                         // Assume little-endian => first value is low priority and last is high priority.
    64                         v = {
    65                         #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    66                                 (unsigned char)0,                                               // padding
    67                                 (unsigned char)referenceCost,                   // low priority
    68                                 (unsigned char)(specCost + correctb),   // correct for signedness
    69                                 (unsigned char)varCost,
    70                                 (unsigned char)signCost,
    71                                 (unsigned char)safeCost,
    72                                 (unsigned char)polyCost,
    73                                 (unsigned char)unsafeCost,                              // high priority
    74                         #else
    75                                 #error Cost BIG_ENDIAN unsupported
    76                         #endif
    77                         };
    78                 }
     81        int get_unsafeCost() const { return v.unsafeCost; }
     82        int get_polyCost() const { return v.polyCost; }
     83        int get_safeCost() const { return v.safeCost; }
     84        int get_signCost() const { return v.signCost; }
     85        int get_varCost() const { return v.varCost; }
     86        int get_specCost() const { return -(correctb - v.specCost); }
     87        int get_referenceCost() const { return v.referenceCost; }
    7988
    80                 int get_unsafeCost() const { return v.unsafeCost; }
    81                 int get_polyCost() const { return v.polyCost; }
    82                 int get_safeCost() const { return v.safeCost; }
    83                 int get_signCost() const { return v.signCost; }
    84                 int get_varCost() const { return v.varCost; }
    85                 int get_specCost() const { return -(correctb - v.specCost); }
    86                 int get_referenceCost() const { return v.referenceCost; }
     89        friend bool operator==( const Cost, const Cost );
     90        friend bool operator!=( const Cost lhs, const Cost rhs );
     91        // returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs
     92        int compare( const Cost rhs ) const {
     93                if ( all == infinity ) return 1;
     94                if ( rhs.all == infinity ) return -1;
     95                return all > rhs.all ? 1 : all == rhs.all ? 0 : -1;
     96        }
     97        friend bool operator<( const Cost lhs, const Cost rhs );
    8798
    88                 friend bool operator==( const Cost, const Cost );
    89                 friend bool operator!=( const Cost lhs, const Cost rhs );
    90                 // returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs
    91                 int compare( const Cost rhs ) const {
    92                         if ( all == infinity ) return 1;
    93                         if ( rhs.all == infinity ) return -1;
    94                         return all > rhs.all ? 1 : all == rhs.all ? 0 : -1;
    95                 }
    96                 friend bool operator<( const Cost lhs, const Cost rhs );
     99        friend Cost operator+( const Cost lhs, const Cost rhs );
    97100
    98                 friend Cost operator+( const Cost lhs, const Cost rhs );
    99  
    100                 Cost operator+=( const Cost rhs ) {
    101                         if ( all == infinity ) return *this;
    102                         if ( rhs.all == infinity ) {
    103                                 all = infinity;
    104                                 return *this;
    105                         }
    106                         all += rhs.all - correctw;                                      // correct for negative spec cost
     101        Cost operator+=( const Cost rhs ) {
     102                if ( all == infinity ) return *this;
     103                if ( rhs.all == infinity ) {
     104                        all = infinity;
    107105                        return *this;
    108106                }
    109 
    110                 Cost incUnsafe( int inc = 1 ) {
    111                         if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; }
    112                         return *this;
    113                 }
    114 
    115                 Cost incPoly( int inc = 1 ) {
    116                         if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; }
    117                         return *this;
    118                 }
    119 
    120                 Cost incSafe( int inc = 1 ) {
    121                         if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; }
    122                         return *this;
    123                 }
    124 
    125                 Cost incSign( int inc = 1 ) {
    126                         if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; }
    127                         return *this;
    128                 }
    129 
    130                 Cost incVar( int inc = 1 ) {
    131                         if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; }
    132                         return *this;
    133                 }
    134 
    135                 Cost decSpec( int dec = 1 ) {
    136                         if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; }
    137                         return *this;
    138                 }
    139 
    140                 Cost incReference( int inc = 1 ) {
    141                         if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; }
    142                         return *this;
    143                 }
    144 
    145                 friend std::ostream & operator<<( std::ostream & os, const Cost cost );
    146         };
    147 
    148         inline bool operator==( const Cost lhs, const Cost rhs ) {
    149                 return lhs.all == rhs.all;
     107                all += rhs.all - correctw;                                      // correct for negative spec cost
     108                return *this;
    150109        }
    151110
    152         inline bool operator!=( const Cost lhs, const Cost rhs ) {
    153                 return !( lhs.all == rhs.all );
     111        Cost incUnsafe( int inc = 1 ) {
     112                if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; }
     113                return *this;
    154114        }
    155115
    156         inline bool operator<( const Cost lhs, const Cost rhs ) {
    157                 if ( lhs.all == Cost::infinity ) return false;
    158                 if ( rhs.all == Cost::infinity ) return true;
    159                 return lhs.all < rhs.all;
     116        Cost incPoly( int inc = 1 ) {
     117                if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; }
     118                return *this;
    160119        }
    161120
    162         inline Cost operator+( const Cost lhs, const Cost rhs ) {
    163                 if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity };
    164                 return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost
     121        Cost incSafe( int inc = 1 ) {
     122                if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; }
     123                return *this;
    165124        }
    166125
    167         inline std::ostream & operator<<( std::ostream & os, const Cost cost ) {
    168                 return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost()
    169                                   << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost()
    170                                   << ", " << cost.get_referenceCost() << " )";
     126        Cost incSign( int inc = 1 ) {
     127                if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; }
     128                return *this;
    171129        }
     130
     131        Cost incVar( int inc = 1 ) {
     132                if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; }
     133                return *this;
     134        }
     135
     136        Cost decSpec( int dec = 1 ) {
     137                if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; }
     138                return *this;
     139        }
     140
     141        Cost incReference( int inc = 1 ) {
     142                if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; }
     143                return *this;
     144        }
     145
     146        friend std::ostream & operator<<( std::ostream & os, const Cost cost );
     147};
     148
     149inline bool operator==( const Cost lhs, const Cost rhs ) {
     150        return lhs.all == rhs.all;
     151}
     152
     153inline bool operator!=( const Cost lhs, const Cost rhs ) {
     154        return !( lhs.all == rhs.all );
     155}
     156
     157inline bool operator<( const Cost lhs, const Cost rhs ) {
     158        if ( lhs.all == Cost::infinity ) return false;
     159        if ( rhs.all == Cost::infinity ) return true;
     160        return lhs.all < rhs.all;
     161}
     162
     163inline Cost operator+( const Cost lhs, const Cost rhs ) {
     164        if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity };
     165        return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost
     166}
     167
     168inline std::ostream & operator<<( std::ostream & os, const Cost cost ) {
     169        return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost()
     170                          << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost()
     171                          << ", " << cost.get_referenceCost() << " )";
     172}
     173
    172174} // namespace ResolvExpr
    173175
  • src/ResolvExpr/CurrentObject.cc

    r16e0dcb rf7f997a  
    4141
    4242namespace ast {
    43         /// Iterates members of a type by initializer.
    44         class MemberIterator {
    45         public:
    46                 virtual ~MemberIterator() {}
    47 
    48                 /// Internal set position based on iterator ranges.
    49                 virtual void setPosition(
    50                         std::deque< ptr< Expr > >::const_iterator it,
    51                         std::deque< ptr< Expr > >::const_iterator end ) = 0;
    52 
    53                 /// Walks the current object using the given designators as a guide.
    54                 void setPosition( const std::deque< ptr< Expr > > & designators ) {
    55                         setPosition( designators.begin(), designators.end() );
    56                 }
    57 
    58                 /// Retrieve the list of possible (Type,Designation) pairs for the
    59                 /// current position in the current object.
    60                 virtual std::deque< InitAlternative > operator* () const = 0;
    61 
    62                 /// True if the iterator is not currently at the end.
    63                 virtual operator bool() const = 0;
    64 
    65                 /// Moves the iterator by one member in the current object.
    66                 virtual MemberIterator & bigStep() = 0;
    67 
    68                 /// Moves the iterator by one member in the current subobject.
    69                 virtual MemberIterator & smallStep() = 0;
    70 
    71                 /// The type of the current object.
    72                 virtual const Type * getType() = 0;
    73 
    74                 /// The type of the current subobject.
    75                 virtual const Type * getNext() = 0;
    76 
    77                 /// Helper for operator*; aggregates must add designator to each init
    78                 /// alternative, but adding designators in operator* creates duplicates.
    79                 virtual std::deque< InitAlternative > first() const = 0;
    80         };
    81 
    82         /// create a new MemberIterator that traverses a type correctly
    83         MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
    84 
    85         /// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry
    86         class SimpleIterator final : public MemberIterator {
    87                 CodeLocation location;
    88                 const Type * type = nullptr;
    89         public:
    90                 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
    91 
    92                 void setPosition(
    93                         std::deque< ptr< Expr > >::const_iterator begin,
    94                         std::deque< ptr< Expr > >::const_iterator end
    95                 ) override {
    96                         if ( begin != end ) {
    97                                 SemanticError( location, "Un-designated initializer given non-empty designator" );
    98                         }
    99                 }
    100 
    101                 std::deque< InitAlternative > operator* () const override { return first(); }
    102 
    103                 operator bool() const override { return type; }
    104 
    105                 SimpleIterator & bigStep() override { return smallStep(); }
    106                 SimpleIterator & smallStep() override {
    107                         type = nullptr;  // empty on increment because no members
    108                         return *this;
    109                 }
    110 
    111                 const Type * getType() override { return type; }
    112 
    113                 const Type * getNext() override { return type; }
    114 
    115                 std::deque< InitAlternative > first() const override {
    116                         if ( type ) return { InitAlternative{ type, new Designation{ location } } };
    117                         return {};
    118                 }
    119         };
    120 
    121         /// Iterates over an indexed type:
    122         class IndexIterator : public MemberIterator {
    123         protected:
    124                 CodeLocation location;
    125                 size_t index = 0;
    126                 size_t size = 0;
    127                 std::unique_ptr<MemberIterator> memberIter;
    128         public:
    129                 IndexIterator( const CodeLocation & loc, size_t size ) :
    130                         location( loc ), size( size )
    131                 {}
    132 
    133                 void setPosition( const Expr * expr ) {
    134                         // need to permit integer-constant-expressions, including: integer constants,
    135                         // enumeration constants, character constants, sizeof expressions, alignof expressions,
    136                         // cast expressions
    137 
    138                         auto arg = eval( expr );
    139                         assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" );
    140                         index = arg.knownValue;
    141 
    142                         // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
    143                         //      try {
    144                         //              index = constExpr->intValue();
    145                         //      } catch ( SemanticErrorException & ) {
    146                         //              SemanticError( expr, "Constant expression of non-integral type in array designator: " );
    147                         //      }
    148                         // } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
    149                         //      setPosition( castExpr->arg );
    150                         // } else if ( dynamic_cast< const SizeofExpr * >( expr ) || dynamic_cast< const AlignofExpr * >( expr ) ) {
    151                         //      index = 0;
    152                         // } else {
    153                         //      assertf( false, "2 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
    154                         // }
    155                 }
    156 
    157                 void setPosition(
    158                         std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
    159                         std::deque<ast::ptr<ast::Expr>>::const_iterator end
    160                 ) override {
    161                         if ( begin == end ) return;
    162 
    163                         setPosition( *begin );
    164                         memberIter->setPosition( ++begin, end );
    165                 }
    166 
    167                 std::deque< InitAlternative > operator* () const override { return first(); }
    168 
    169                 operator bool() const override { return index < size; }
    170         };
    171 
    172         /// Iterates over the members of array types:
    173         class ArrayIterator final : public IndexIterator {
    174                 const ArrayType * array = nullptr;
    175                 const Type * base = nullptr;
    176 
    177                 size_t getSize( const Expr * expr ) {
    178                         auto res = eval( expr );
    179                         if ( !res.hasKnownValue ) {
    180                                 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
    181                         }
    182                         return res.knownValue;
    183                 }
    184 
    185         public:
    186                 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) :
    187                                 IndexIterator( loc, getSize( at->dimension) ),
    188                                 array( at ), base( at->base ) {
    189                         PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
    190                         memberIter.reset( createMemberIterator( loc, base ) );
    191                         if ( at->isVarLen ) {
    192                                 SemanticError( location, at, "VLA initialization does not support @=: " );
    193                         }
    194                 }
    195 
    196                 ArrayIterator & bigStep() override {
    197                         PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    198                         ++index;
    199                         memberIter.reset( index < size ? createMemberIterator( location, base ) : nullptr );
    200                         return *this;
    201                 }
    202 
    203                 ArrayIterator & smallStep() override {
    204                         PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    205                         if ( memberIter ) {
    206                                 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
    207                                 memberIter->smallStep();
    208                                 if ( *memberIter ) {
    209                                         PRINT( std::cerr << "has valid member iter" << std::endl; )
    210                                         return *this;
    211                                 }
    212                         }
    213                         return bigStep();
    214                 }
    215 
    216                 const Type * getType() override { return array; }
    217 
    218                 const Type * getNext() override { return base; }
    219 
    220                 std::deque< InitAlternative > first() const override {
    221                         PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    222                         if ( memberIter && *memberIter ) {
    223                                 std::deque< InitAlternative > ret = memberIter->first();
    224                                 for ( InitAlternative & alt : ret ) {
    225                                         alt.designation.get_and_mutate()->designators.emplace_front( ConstantExpr::from_ulong( location, index ) );
    226                                 }
    227                                 return ret;
    228                         }
    229                         return {};
    230                 }
    231         };
    232 
    233         class AggregateIterator : public MemberIterator {
    234         protected:
    235                 using MemberList = std::vector< ptr< Decl > >;
    236 
    237                 CodeLocation location;
    238                 std::string kind;  // for debug
    239                 std::string name;
    240                 const Type * inst;
    241                 const MemberList & members;
    242                 MemberList::const_iterator curMember;
    243                 bool atbegin = true;  // false at first {small,big}Step
    244                 const Type * curType = nullptr;
    245                 std::unique_ptr< MemberIterator > memberIter = nullptr;
    246                 TypeSubstitution sub;
    247 
    248                 bool init() {
    249                         PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
    250                         if ( curMember != members.end() ) {
    251                                 if ( auto field = curMember->as< ObjectDecl >() ) {
    252                                         PRINT( std::cerr << "incremented to field: " << field << std::endl; )
    253                                         curType = field->get_type();
    254                                         memberIter.reset( createMemberIterator( location, curType ) );
    255                                         return true;
    256                                 }
    257                         }
    258                         return false;
    259                 }
    260 
    261                 AggregateIterator(
    262                         const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
    263                         const MemberList & ms )
    264                 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
    265                   sub( genericSubstitution( i ) ) {
    266                         PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
    267                         init();
    268                 }
    269 
    270         public:
    271                 void setPosition(
    272                         std::deque< ptr< Expr > >::const_iterator begin,
    273                         std::deque< ptr< Expr > >::const_iterator end
    274                 ) final {
    275                         if ( begin == end ) return;
    276 
    277                         if ( auto varExpr = begin->as< VariableExpr >() ) {
    278                                 for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
    279                                         if ( *curMember != varExpr->var ) continue;
    280 
    281                                         ++begin;
    282 
    283                                         memberIter.reset( createMemberIterator( location, varExpr->result ) );
    284                                         curType = varExpr->result;
    285                                         atbegin = curMember == members.begin() && begin == end;
    286                                         memberIter->setPosition( begin, end );
    287                                         return;
    288                                 }
    289                                 assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    290                         } else {
    291                                 assertf( false, "1 bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
    292                         }
    293                 }
    294 
    295                 std::deque< InitAlternative > operator* () const final {
    296                         if ( memberIter && *memberIter ) {
    297                                 std::deque< InitAlternative > ret = memberIter->first();
    298                                 PRINT( std::cerr << "sub: " << sub << std::endl; )
    299                                 for ( InitAlternative & alt : ret ) {
    300                                         PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    301                                         alt.designation.get_and_mutate()->designators.emplace_front(
    302                                                 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    303                                         // need to substitute for generic types so that casts are to concrete types
    304                                         alt.type = shallowCopy(alt.type.get());
    305                                         PRINT( std::cerr << "  type is: " << alt.type; )
    306                                         sub.apply( alt.type ); // also apply to designation??
    307                                         PRINT( std::cerr << " ==> " << alt.type << std::endl; )
    308                                 }
    309                                 return ret;
    310                         }
    311                         return {};
    312                 }
    313 
    314                 AggregateIterator & smallStep() final {
    315                         PRINT( std::cerr << "smallStep in " << kind << std::endl; )
    316                         atbegin = false;
    317                         if ( memberIter ) {
    318                                 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
    319                                 memberIter->smallStep();
    320                                 if ( *memberIter ) {
    321                                         PRINT( std::cerr << "success!" << std::endl; )
    322                                         return *this;
    323                                 }
    324                         }
    325                         return bigStep();
    326                 }
    327 
    328                 AggregateIterator & bigStep() override = 0;
    329 
    330                 const Type * getType() final { return inst; }
    331 
    332                 const Type * getNext() final {
    333                         bool hasMember = memberIter && *memberIter;
    334                         return hasMember ? memberIter->getType() : nullptr;
    335                 }
    336 
    337                 std::deque< InitAlternative > first() const final {
    338                         std::deque< InitAlternative > ret;
    339                         PRINT( std::cerr << "first " << kind << std::endl; )
    340                         if ( memberIter && *memberIter ) {
    341                                 PRINT( std::cerr << "adding children" << std::endl; )
    342                                 ret = memberIter->first();
    343                                 for ( InitAlternative & alt : ret ) {
    344                                         PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    345                                         alt.designation.get_and_mutate()->designators.emplace_front(
    346                                                 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    347                                 }
    348                         }
    349                         if ( atbegin ) {
    350                                 // only add self if at the very beginning of the structure
    351                                 PRINT( std::cerr << "adding self" << std::endl; )
    352                                 ret.emplace_front( inst, new Designation{ location } );
     43
     44/// Iterates members of a type by initializer.
     45class MemberIterator {
     46public:
     47        virtual ~MemberIterator() {}
     48
     49        /// Internal set position based on iterator ranges.
     50        virtual void setPosition(
     51                std::deque< ptr< Expr > >::const_iterator it,
     52                std::deque< ptr< Expr > >::const_iterator end ) = 0;
     53
     54        /// Walks the current object using the given designators as a guide.
     55        void setPosition( const std::deque< ptr< Expr > > & designators ) {
     56                setPosition( designators.begin(), designators.end() );
     57        }
     58
     59        /// Retrieve the list of possible (Type,Designation) pairs for the
     60        /// current position in the current object.
     61        virtual std::deque< InitAlternative > operator* () const = 0;
     62
     63        /// True if the iterator is not currently at the end.
     64        virtual operator bool() const = 0;
     65
     66        /// Moves the iterator by one member in the current object.
     67        virtual MemberIterator & bigStep() = 0;
     68
     69        /// Moves the iterator by one member in the current subobject.
     70        virtual MemberIterator & smallStep() = 0;
     71
     72        /// The type of the current object.
     73        virtual const Type * getType() = 0;
     74
     75        /// The type of the current subobject.
     76        virtual const Type * getNext() = 0;
     77
     78        /// Helper for operator*; aggregates must add designator to each init
     79        /// alternative, but adding designators in operator* creates duplicates.
     80        virtual std::deque< InitAlternative > first() const = 0;
     81};
     82
     83namespace {
     84
     85/// create a new MemberIterator that traverses a type correctly
     86MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
     87
     88/// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry
     89class SimpleIterator final : public MemberIterator {
     90        CodeLocation location;
     91        const Type * type = nullptr;
     92public:
     93        SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
     94
     95        void setPosition(
     96                std::deque< ptr< Expr > >::const_iterator begin,
     97                std::deque< ptr< Expr > >::const_iterator end
     98        ) override {
     99                if ( begin != end ) {
     100                        SemanticError( location, "Un-designated initializer given non-empty designator" );
     101                }
     102        }
     103
     104        std::deque< InitAlternative > operator* () const override { return first(); }
     105
     106        operator bool() const override { return type; }
     107
     108        SimpleIterator & bigStep() override { return smallStep(); }
     109        SimpleIterator & smallStep() override {
     110                type = nullptr;  // empty on increment because no members
     111                return *this;
     112        }
     113
     114        const Type * getType() override { return type; }
     115
     116        const Type * getNext() override { return type; }
     117
     118        std::deque< InitAlternative > first() const override {
     119                if ( type ) return { InitAlternative{ type, new Designation{ location } } };
     120                return {};
     121        }
     122};
     123
     124/// Iterates over an indexed type:
     125class IndexIterator : public MemberIterator {
     126protected:
     127        CodeLocation location;
     128        size_t index = 0;
     129        size_t size = 0;
     130        std::unique_ptr<MemberIterator> memberIter;
     131public:
     132        IndexIterator( const CodeLocation & loc, size_t size ) :
     133                location( loc ), size( size )
     134        {}
     135
     136        void setPosition( const Expr * expr ) {
     137                // need to permit integer-constant-expressions, including: integer constants,
     138                // enumeration constants, character constants, sizeof expressions, alignof expressions,
     139                // cast expressions
     140
     141                auto arg = eval( expr );
     142                assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" );
     143                index = arg.knownValue;
     144
     145                // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     146                //      try {
     147                //              index = constExpr->intValue();
     148                //      } catch ( SemanticErrorException & ) {
     149                //              SemanticError( expr, "Constant expression of non-integral type in array designator: " );
     150                //      }
     151                // } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
     152                //      setPosition( castExpr->arg );
     153                // } else if ( dynamic_cast< const SizeofExpr * >( expr ) || dynamic_cast< const AlignofExpr * >( expr ) ) {
     154                //      index = 0;
     155                // } else {
     156                //      assertf( false, "2 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
     157                // }
     158        }
     159
     160        void setPosition(
     161                std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
     162                std::deque<ast::ptr<ast::Expr>>::const_iterator end
     163        ) override {
     164                if ( begin == end ) return;
     165
     166                setPosition( *begin );
     167                memberIter->setPosition( ++begin, end );
     168        }
     169
     170        std::deque< InitAlternative > operator* () const override { return first(); }
     171
     172        operator bool() const override { return index < size; }
     173};
     174
     175/// Iterates over the members of array types:
     176class ArrayIterator final : public IndexIterator {
     177        const ArrayType * array = nullptr;
     178        const Type * base = nullptr;
     179
     180        size_t getSize( const Expr * expr ) {
     181                auto res = eval( expr );
     182                if ( !res.hasKnownValue ) {
     183                        SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
     184                }
     185                return res.knownValue;
     186        }
     187
     188public:
     189        ArrayIterator( const CodeLocation & loc, const ArrayType * at ) :
     190                        IndexIterator( loc, getSize( at->dimension) ),
     191                        array( at ), base( at->base ) {
     192                PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     193                memberIter.reset( createMemberIterator( loc, base ) );
     194                if ( at->isVarLen ) {
     195                        SemanticError( location, at, "VLA initialization does not support @=: " );
     196                }
     197        }
     198
     199        ArrayIterator & bigStep() override {
     200                PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
     201                ++index;
     202                memberIter.reset( index < size ? createMemberIterator( location, base ) : nullptr );
     203                return *this;
     204        }
     205
     206        ArrayIterator & smallStep() override {
     207                PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
     208                if ( memberIter ) {
     209                        PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
     210                        memberIter->smallStep();
     211                        if ( *memberIter ) {
     212                                PRINT( std::cerr << "has valid member iter" << std::endl; )
     213                                return *this;
     214                        }
     215                }
     216                return bigStep();
     217        }
     218
     219        const Type * getType() override { return array; }
     220
     221        const Type * getNext() override { return base; }
     222
     223        std::deque< InitAlternative > first() const override {
     224                PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
     225                if ( memberIter && *memberIter ) {
     226                        std::deque< InitAlternative > ret = memberIter->first();
     227                        for ( InitAlternative & alt : ret ) {
     228                                alt.designation.get_and_mutate()->designators.emplace_front( ConstantExpr::from_ulong( location, index ) );
    353229                        }
    354230                        return ret;
    355231                }
    356         };
    357 
    358         class StructIterator final : public AggregateIterator {
    359         public:
    360                 StructIterator( const CodeLocation & loc, const StructInstType * inst )
    361                 : AggregateIterator( loc, "StructIterator", inst->name, inst, inst->base->members ) {}
    362 
    363                 operator bool() const override {
    364                         return curMember != members.end() || (memberIter && *memberIter);
    365                 }
    366 
    367                 StructIterator & bigStep() override {
    368                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    369                         atbegin = false;
    370                         memberIter = nullptr;
    371                         curType = nullptr;
    372                         while ( curMember != members.end() ) {
    373                                 ++curMember;
    374                                 if ( init() ) return *this;
    375                         }
    376                         return *this;
    377                 }
    378         };
    379 
    380         class UnionIterator final : public AggregateIterator {
    381         public:
    382                 UnionIterator( const CodeLocation & loc, const UnionInstType * inst )
    383                 : AggregateIterator( loc, "UnionIterator", inst->name, inst, inst->base->members ) {}
    384 
    385                 operator bool() const override { return memberIter && *memberIter; }
    386 
    387                 UnionIterator & bigStep() override {
    388                         // unions only initialize one member
    389                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    390                         atbegin = false;
    391                         memberIter = nullptr;
    392                         curType = nullptr;
    393                         curMember = members.end();
    394                         return *this;
    395                 }
    396         };
    397 
    398         /// Iterates across the positions in a tuple:
    399         class TupleIterator final : public IndexIterator {
    400                 ast::TupleType const * const tuple;
    401 
    402                 const ast::Type * typeAtIndex() const {
    403                         assert( index < size );
    404                         return tuple->types[ index ].get();
    405                 }
    406 
    407         public:
    408                 TupleIterator( const CodeLocation & loc, const TupleType * type )
    409                 : IndexIterator( loc, type->size() ), tuple( type ) {
    410                         PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; )
    411                         memberIter.reset( createMemberIterator( loc, typeAtIndex() ) );
    412                 }
    413 
    414                 TupleIterator & bigStep() override {
    415                         ++index;
    416                         memberIter.reset( index < size ?
    417                                 createMemberIterator( location, typeAtIndex() ) : nullptr );
    418                         return *this;
    419                 }
    420 
    421                 TupleIterator & smallStep() override {
    422                         if ( memberIter ) {
    423                                 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
    424                                 memberIter->smallStep();
    425                                 if ( !memberIter ) {
    426                                         PRINT( std::cerr << "has valid member iter" << std::endl; )
    427                                         return *this;
    428                                 }
    429                         }
    430                         return bigStep();
    431                 }
    432 
    433                 const ast::Type * getType() override {
    434                         return tuple;
    435                 }
    436 
    437                 const ast::Type * getNext() override {
    438                         bool hasMember = memberIter && *memberIter;
    439                         return hasMember ? memberIter->getType() : nullptr;
    440                 }
    441 
    442                 std::deque< InitAlternative > first() const override {
    443                         PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; )
    444                         if ( memberIter && *memberIter ) {
    445                                 std::deque< InitAlternative > ret = memberIter->first();
    446                                 for ( InitAlternative & alt : ret ) {
    447                                         alt.designation.get_and_mutate()->designators.emplace_front(
    448                                                 ConstantExpr::from_ulong( location, index ) );
    449                                 }
    450                                 return ret;
    451                         }
    452                         return {};
    453                 }
    454         };
    455 
    456         MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) {
    457                 if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
    458                         if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
    459                                 assert( sit->base );
    460                                 return new StructIterator{ loc, sit };
    461                         } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) {
    462                                 assert( uit->base );
    463                                 return new UnionIterator{ loc, uit };
    464                         } else {
    465                                 assertf(
    466                                         dynamic_cast< const EnumInstType * >( type )
    467                                                 || dynamic_cast< const TypeInstType * >( type ),
    468                                         "Encountered unhandled BaseInstType in createMemberIterator: %s",
    469                                                 toString( type ).c_str() );
    470                                 return new SimpleIterator{ loc, type };
    471                         }
    472                 } else if ( auto at = dynamic_cast< const ArrayType * >( type ) ) {
    473                         return new ArrayIterator{ loc, at };
    474                 } else if ( auto tt = dynamic_cast< const TupleType * >( type ) ) {
    475                         return new TupleIterator{ loc, tt };
     232                return {};
     233        }
     234};
     235
     236class AggregateIterator : public MemberIterator {
     237protected:
     238        using MemberList = std::vector< ptr< Decl > >;
     239
     240        CodeLocation location;
     241        std::string kind;  // for debug
     242        std::string name;
     243        const Type * inst;
     244        const MemberList & members;
     245        MemberList::const_iterator curMember;
     246        bool atbegin = true;  // false at first {small,big}Step
     247        const Type * curType = nullptr;
     248        std::unique_ptr< MemberIterator > memberIter = nullptr;
     249        TypeSubstitution sub;
     250
     251        bool init() {
     252                PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
     253                if ( curMember != members.end() ) {
     254                        if ( auto field = curMember->as< ObjectDecl >() ) {
     255                                PRINT( std::cerr << "incremented to field: " << field << std::endl; )
     256                                curType = field->get_type();
     257                                memberIter.reset( createMemberIterator( location, curType ) );
     258                                return true;
     259                        }
     260                }
     261                return false;
     262        }
     263
     264        AggregateIterator(
     265                const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
     266                const MemberList & ms )
     267        : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
     268          sub( genericSubstitution( i ) ) {
     269                PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
     270                init();
     271        }
     272
     273public:
     274        void setPosition(
     275                std::deque< ptr< Expr > >::const_iterator begin,
     276                std::deque< ptr< Expr > >::const_iterator end
     277        ) final {
     278                if ( begin == end ) return;
     279
     280                if ( auto varExpr = begin->as< VariableExpr >() ) {
     281                        for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
     282                                if ( *curMember != varExpr->var ) continue;
     283
     284                                ++begin;
     285
     286                                memberIter.reset( createMemberIterator( location, varExpr->result ) );
     287                                curType = varExpr->result;
     288                                atbegin = curMember == members.begin() && begin == end;
     289                                memberIter->setPosition( begin, end );
     290                                return;
     291                        }
     292                        assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    476293                } else {
     294                        assertf( false, "1 bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
     295                }
     296        }
     297
     298        std::deque< InitAlternative > operator* () const final {
     299                if ( memberIter && *memberIter ) {
     300                        std::deque< InitAlternative > ret = memberIter->first();
     301                        PRINT( std::cerr << "sub: " << sub << std::endl; )
     302                        for ( InitAlternative & alt : ret ) {
     303                                PRINT( std::cerr << "iterating and adding designators" << std::endl; )
     304                                alt.designation.get_and_mutate()->designators.emplace_front(
     305                                        new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
     306                                // need to substitute for generic types so that casts are to concrete types
     307                                alt.type = shallowCopy(alt.type.get());
     308                                PRINT( std::cerr << "  type is: " << alt.type; )
     309                                sub.apply( alt.type ); // also apply to designation??
     310                                PRINT( std::cerr << " ==> " << alt.type << std::endl; )
     311                        }
     312                        return ret;
     313                }
     314                return {};
     315        }
     316
     317        AggregateIterator & smallStep() final {
     318                PRINT( std::cerr << "smallStep in " << kind << std::endl; )
     319                atbegin = false;
     320                if ( memberIter ) {
     321                        PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
     322                        memberIter->smallStep();
     323                        if ( *memberIter ) {
     324                                PRINT( std::cerr << "success!" << std::endl; )
     325                                return *this;
     326                        }
     327                }
     328                return bigStep();
     329        }
     330
     331        AggregateIterator & bigStep() override = 0;
     332
     333        const Type * getType() final { return inst; }
     334
     335        const Type * getNext() final {
     336                bool hasMember = memberIter && *memberIter;
     337                return hasMember ? memberIter->getType() : nullptr;
     338        }
     339
     340        std::deque< InitAlternative > first() const final {
     341                std::deque< InitAlternative > ret;
     342                PRINT( std::cerr << "first " << kind << std::endl; )
     343                if ( memberIter && *memberIter ) {
     344                        PRINT( std::cerr << "adding children" << std::endl; )
     345                        ret = memberIter->first();
     346                        for ( InitAlternative & alt : ret ) {
     347                                PRINT( std::cerr << "iterating and adding designators" << std::endl; )
     348                                alt.designation.get_and_mutate()->designators.emplace_front(
     349                                        new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
     350                        }
     351                }
     352                if ( atbegin ) {
     353                        // only add self if at the very beginning of the structure
     354                        PRINT( std::cerr << "adding self" << std::endl; )
     355                        ret.emplace_front( inst, new Designation{ location } );
     356                }
     357                return ret;
     358        }
     359};
     360
     361class StructIterator final : public AggregateIterator {
     362public:
     363        StructIterator( const CodeLocation & loc, const StructInstType * inst )
     364        : AggregateIterator( loc, "StructIterator", inst->name, inst, inst->base->members ) {}
     365
     366        operator bool() const override {
     367                return curMember != members.end() || (memberIter && *memberIter);
     368        }
     369
     370        StructIterator & bigStep() override {
     371                PRINT( std::cerr << "bigStep in " << kind << std::endl; )
     372                atbegin = false;
     373                memberIter = nullptr;
     374                curType = nullptr;
     375                while ( curMember != members.end() ) {
     376                        ++curMember;
     377                        if ( init() ) return *this;
     378                }
     379                return *this;
     380        }
     381};
     382
     383class UnionIterator final : public AggregateIterator {
     384public:
     385        UnionIterator( const CodeLocation & loc, const UnionInstType * inst )
     386        : AggregateIterator( loc, "UnionIterator", inst->name, inst, inst->base->members ) {}
     387
     388        operator bool() const override { return memberIter && *memberIter; }
     389
     390        UnionIterator & bigStep() override {
     391                // unions only initialize one member
     392                PRINT( std::cerr << "bigStep in " << kind << std::endl; )
     393                atbegin = false;
     394                memberIter = nullptr;
     395                curType = nullptr;
     396                curMember = members.end();
     397                return *this;
     398        }
     399};
     400
     401/// Iterates across the positions in a tuple:
     402class TupleIterator final : public IndexIterator {
     403        ast::TupleType const * const tuple;
     404
     405        const ast::Type * typeAtIndex() const {
     406                assert( index < size );
     407                return tuple->types[ index ].get();
     408        }
     409
     410public:
     411        TupleIterator( const CodeLocation & loc, const TupleType * type )
     412        : IndexIterator( loc, type->size() ), tuple( type ) {
     413                PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; )
     414                memberIter.reset( createMemberIterator( loc, typeAtIndex() ) );
     415        }
     416
     417        TupleIterator & bigStep() override {
     418                ++index;
     419                memberIter.reset( index < size ?
     420                        createMemberIterator( location, typeAtIndex() ) : nullptr );
     421                return *this;
     422        }
     423
     424        TupleIterator & smallStep() override {
     425                if ( memberIter ) {
     426                        PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
     427                        memberIter->smallStep();
     428                        if ( !memberIter ) {
     429                                PRINT( std::cerr << "has valid member iter" << std::endl; )
     430                                return *this;
     431                        }
     432                }
     433                return bigStep();
     434        }
     435
     436        const ast::Type * getType() override {
     437                return tuple;
     438        }
     439
     440        const ast::Type * getNext() override {
     441                bool hasMember = memberIter && *memberIter;
     442                return hasMember ? memberIter->getType() : nullptr;
     443        }
     444
     445        std::deque< InitAlternative > first() const override {
     446                PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; )
     447                if ( memberIter && *memberIter ) {
     448                        std::deque< InitAlternative > ret = memberIter->first();
     449                        for ( InitAlternative & alt : ret ) {
     450                                alt.designation.get_and_mutate()->designators.emplace_front(
     451                                        ConstantExpr::from_ulong( location, index ) );
     452                        }
     453                        return ret;
     454                }
     455                return {};
     456        }
     457};
     458
     459MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) {
     460        if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
     461                if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
     462                        assert( sit->base );
     463                        return new StructIterator{ loc, sit };
     464                } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) {
     465                        assert( uit->base );
     466                        return new UnionIterator{ loc, uit };
     467                } else {
     468                        assertf(
     469                                dynamic_cast< const EnumInstType * >( type )
     470                                        || dynamic_cast< const TypeInstType * >( type ),
     471                                "Encountered unhandled BaseInstType in createMemberIterator: %s",
     472                                        toString( type ).c_str() );
    477473                        return new SimpleIterator{ loc, type };
    478474                }
    479         }
    480 
    481         CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() {
    482                 objStack.emplace_back( new SimpleIterator{ loc, type } );
    483         }
    484 
    485         const Designation * CurrentObject::findNext( const Designation * designation ) {
    486                 using DesignatorChain = std::deque< ptr< Expr > >;
    487                 PRINT( std::cerr << "___findNext" << std::endl; )
    488 
    489                 // find all the d's
    490                 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
    491                 std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes;
    492                 for ( const Expr * expr : designation->designators ) {
    493                         PRINT( std::cerr << "____untyped: " << expr << std::endl; )
    494                         auto dit = desigAlts.begin();
    495 
    496                         for ( const Type * t : curTypes ) {
    497                                 assert( dit != desigAlts.end() );
    498                                 DesignatorChain & d = *dit;
    499                                 if ( auto nexpr = dynamic_cast< const NameExpr *>( expr ) ) {
    500                                         PRINT( std::cerr << "____actual: " << t << std::endl; )
    501                                         if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) {
    502                                                 // concatenate identical field names
    503                                                 for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
    504                                                         if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
    505                                                                 PRINT( std::cerr << "____alt: " << field->type << std::endl; )
    506                                                                 DesignatorChain d2 = d;
    507                                                                 d2.emplace_back( new VariableExpr{ expr->location, field } );
    508                                                                 newDesigAlts.emplace_back( std::move( d2 ) );
    509                                                                 newTypes.emplace_back( field->type );
    510                                                         }
    511                                                 }
    512                                         } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
    513                                                 auto nexpr = dynamic_cast< const NameExpr *>( expr );
    514                                                 for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
    515                                                         if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
    516                                                                 DesignatorChain d2 = d;
    517                                                                 d2.emplace_back( new VariableExpr{ expr->location, field } );
    518                                                                 newDesigAlts.emplace_back( std::move( d2 ) );
    519                                                                 newTypes.emplace_back( at->base );
    520                                                         }
     475        } else if ( auto at = dynamic_cast< const ArrayType * >( type ) ) {
     476                return new ArrayIterator{ loc, at };
     477        } else if ( auto tt = dynamic_cast< const TupleType * >( type ) ) {
     478                return new TupleIterator{ loc, tt };
     479        } else {
     480                return new SimpleIterator{ loc, type };
     481        }
     482}
     483
     484} // namespace
     485
     486CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() {
     487        objStack.emplace_back( new SimpleIterator{ loc, type } );
     488}
     489
     490const Designation * CurrentObject::findNext( const Designation * designation ) {
     491        using DesignatorChain = std::deque< ptr< Expr > >;
     492        PRINT( std::cerr << "___findNext" << std::endl; )
     493
     494        // find all the d's
     495        std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
     496        std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes;
     497        for ( const Expr * expr : designation->designators ) {
     498                PRINT( std::cerr << "____untyped: " << expr << std::endl; )
     499                auto dit = desigAlts.begin();
     500
     501                for ( const Type * t : curTypes ) {
     502                        assert( dit != desigAlts.end() );
     503                        DesignatorChain & d = *dit;
     504                        if ( auto nexpr = dynamic_cast< const NameExpr *>( expr ) ) {
     505                                PRINT( std::cerr << "____actual: " << t << std::endl; )
     506                                if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) {
     507                                        // concatenate identical field names
     508                                        for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
     509                                                if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
     510                                                        PRINT( std::cerr << "____alt: " << field->type << std::endl; )
     511                                                        DesignatorChain d2 = d;
     512                                                        d2.emplace_back( new VariableExpr{ expr->location, field } );
     513                                                        newDesigAlts.emplace_back( std::move( d2 ) );
     514                                                        newTypes.emplace_back( field->type );
    521515                                                }
    522516                                        }
    523 
    524                                         ++dit;
    525                                 } else {
    526                                         if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
    527                                                 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
    528                                                 d.emplace_back( expr );
    529                                                 newDesigAlts.emplace_back( d );
    530                                                 newTypes.emplace_back( at->base );
     517                                } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
     518                                        auto nexpr = dynamic_cast< const NameExpr *>( expr );
     519                                        for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
     520                                                if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
     521                                                        DesignatorChain d2 = d;
     522                                                        d2.emplace_back( new VariableExpr{ expr->location, field } );
     523                                                        newDesigAlts.emplace_back( std::move( d2 ) );
     524                                                        newTypes.emplace_back( at->base );
     525                                                }
    531526                                        }
    532527                                }
    533                         }
    534 
    535                         // reset queue
    536                         desigAlts = std::move( newDesigAlts );
    537                         newDesigAlts.clear();
    538                         curTypes = std::move( newTypes );
    539                         newTypes.clear();
    540                         assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
    541                 }
    542 
    543                 if ( desigAlts.size() > 1 ) {
    544                         SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
    545                 } else if ( desigAlts.empty() ) {
    546                         SemanticError( designation, "No reasonable alternatives for designation: " );
    547                 }
    548 
    549                 DesignatorChain & d = desigAlts.back();
    550                 PRINT( for ( Expression * expr : d ) {
    551                         std::cerr << "____desig: " << expr << std::endl;
    552                 } ) // for
    553                 assertf( ! curTypes.empty(), "empty designator chosen");
    554 
    555                 // set new designators
    556                 assertf( ! objStack.empty(), "empty object stack when setting designation" );
    557                 Designation * actualDesignation =
    558                         new Designation{ designation->location, DesignatorChain{d} };
    559                 objStack.back()->setPosition( d ); // destroys d
    560                 return actualDesignation;
    561         }
    562 
    563         void CurrentObject::setNext( const Designation * designation ) {
    564                 PRINT( std::cerr << "____setNext" << designation << std::endl; )
    565                 assertf( ! objStack.empty(), "obj stack empty in setNext" );
    566                 objStack.back()->setPosition( designation->designators );
    567         }
    568 
    569         void CurrentObject::increment() {
    570                 PRINT( std::cerr << "____increment" << std::endl; )
    571                 if ( objStack.empty() ) return;
     528
     529                                ++dit;
     530                        } else {
     531                                if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
     532                                        PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
     533                                        d.emplace_back( expr );
     534                                        newDesigAlts.emplace_back( d );
     535                                        newTypes.emplace_back( at->base );
     536                                }
     537                        }
     538                }
     539
     540                // reset queue
     541                desigAlts = std::move( newDesigAlts );
     542                newDesigAlts.clear();
     543                curTypes = std::move( newTypes );
     544                newTypes.clear();
     545                assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
     546        }
     547
     548        if ( desigAlts.size() > 1 ) {
     549                SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
     550        } else if ( desigAlts.empty() ) {
     551                SemanticError( designation, "No reasonable alternatives for designation: " );
     552        }
     553
     554        DesignatorChain & d = desigAlts.back();
     555        PRINT( for ( Expression * expr : d ) {
     556                std::cerr << "____desig: " << expr << std::endl;
     557        } ) // for
     558        assertf( ! curTypes.empty(), "empty designator chosen");
     559
     560        // set new designators
     561        assertf( ! objStack.empty(), "empty object stack when setting designation" );
     562        Designation * actualDesignation =
     563                new Designation{ designation->location, DesignatorChain{d} };
     564        objStack.back()->setPosition( d ); // destroys d
     565        return actualDesignation;
     566}
     567
     568void CurrentObject::setNext( const Designation * designation ) {
     569        PRINT( std::cerr << "____setNext" << designation << std::endl; )
     570        assertf( ! objStack.empty(), "obj stack empty in setNext" );
     571        objStack.back()->setPosition( designation->designators );
     572}
     573
     574void CurrentObject::increment() {
     575        PRINT( std::cerr << "____increment" << std::endl; )
     576        if ( objStack.empty() ) return;
     577        PRINT( std::cerr << *objStack.back() << std::endl; )
     578        objStack.back()->smallStep();
     579}
     580
     581void CurrentObject::enterListInit( const CodeLocation & loc ) {
     582        PRINT( std::cerr << "____entering list init" << std::endl; )
     583        assertf( ! objStack.empty(), "empty obj stack entering list init" );
     584        const ast::Type * type = objStack.back()->getNext();
     585        assert( type );
     586        objStack.emplace_back( createMemberIterator( loc, type ) );
     587}
     588
     589void CurrentObject::exitListInit() {
     590        PRINT( std::cerr << "____exiting list init" << std::endl; )
     591        assertf( ! objStack.empty(), "objstack empty" );
     592        objStack.pop_back();
     593        if ( ! objStack.empty() ) {
    572594                PRINT( std::cerr << *objStack.back() << std::endl; )
    573                 objStack.back()->smallStep();
    574         }
    575 
    576         void CurrentObject::enterListInit( const CodeLocation & loc ) {
    577                 PRINT( std::cerr << "____entering list init" << std::endl; )
    578                 assertf( ! objStack.empty(), "empty obj stack entering list init" );
    579                 const ast::Type * type = objStack.back()->getNext();
    580                 assert( type );
    581                 objStack.emplace_back( createMemberIterator( loc, type ) );
    582         }
    583 
    584         void CurrentObject::exitListInit() {
    585                 PRINT( std::cerr << "____exiting list init" << std::endl; )
    586                 assertf( ! objStack.empty(), "objstack empty" );
    587                 objStack.pop_back();
    588                 if ( ! objStack.empty() ) {
    589                         PRINT( std::cerr << *objStack.back() << std::endl; )
    590                         objStack.back()->bigStep();
    591                 }
    592         }
    593 
    594         std::deque< InitAlternative > CurrentObject::getOptions() {
    595                 PRINT( std::cerr << "____getting current options" << std::endl; )
    596                 assertf( ! objStack.empty(), "objstack empty in getOptions" );
    597                 return **objStack.back();
    598         }
    599 
    600         const Type * CurrentObject::getCurrentType() {
    601                 PRINT( std::cerr << "____getting current type" << std::endl; )
    602                 assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
    603                 return objStack.back()->getNext();
    604         }
    605 }
     595                objStack.back()->bigStep();
     596        }
     597}
     598
     599std::deque< InitAlternative > CurrentObject::getOptions() {
     600        PRINT( std::cerr << "____getting current options" << std::endl; )
     601        assertf( ! objStack.empty(), "objstack empty in getOptions" );
     602        return **objStack.back();
     603}
     604
     605const Type * CurrentObject::getCurrentType() {
     606        PRINT( std::cerr << "____getting current type" << std::endl; )
     607        assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
     608        return objStack.back()->getNext();
     609}
     610
     611} // namespace ast
    606612
    607613// Local Variables: //
  • src/ResolvExpr/CurrentObject.h

    r16e0dcb rf7f997a  
    1717
    1818#include <deque>
    19 #include <list>   // for list
    2019#include <memory> // for unique_ptr
    21 #include <stack>  // for stack
    2220#include <vector>
    2321
     
    2523#include "Common/CodeLocation.h"
    2624
     25namespace ast {
     26
     27// AST class types:
    2728class Designation;
    2829class Type;
    2930struct InitAlternative;
    3031
    31 namespace ResolvExpr {
    32         class MemberIterator;
     32/// Iterates members of a type by initializer
     33class MemberIterator;
    3334
    34         // TODO: memory management of MemberIterators
    35         class CurrentObject {
    36         public:
    37                 CurrentObject();
    38                 CurrentObject( Type * type );
     35/// Builds initializer lists in resolution
     36class CurrentObject final {
     37        std::vector<std::shared_ptr<MemberIterator>> objStack;
    3938
    40                 /// resolves unresolved designation
    41                 Designation * findNext( Designation * designation );
    42                 /// sets current position using resolved designation
    43                 void setNext( Designation * designation );
    44                 /// steps to next sub-object of current-object
    45                 void increment();
    46                 /// sets new current-object for the duration of this brace-enclosed initializer-list
    47                 void enterListInit();
    48                 /// restores previous current-object
    49                 void exitListInit();
    50                 /// produces a list of alternatives (Type *, Designation *) for the current sub-object's initializer
    51                 std::list< InitAlternative > getOptions();
    52                 /// produces the type of the current object but no subobjects
    53                 Type * getCurrentType();
     39public:
     40        CurrentObject() = default;
     41        CurrentObject( const CodeLocation & loc, const Type * type );
    5442
    55         private:
    56                 std::stack< MemberIterator * > objStack;
    57         };
    58 } // namespace ResolvExpr
     43        /// Resolves unresolved designation.
     44        const Designation * findNext( const Designation * designation );
     45        /// Sets current position using the resolved designation.
     46        void setNext( const Designation * designation );
     47        /// Steps to next sub-object of current object.
     48        void increment();
     49        /// Sets new current object for the duration of this brace-enclosed intializer-list.
     50        void enterListInit( const CodeLocation & loc );
     51        /// Restores previous current object.
     52        void exitListInit();
     53        /// Produces a list of alternatives (Type *, Designation *)
     54        /// for the current sub-object's initializer.
     55        std::deque< InitAlternative > getOptions();
     56        /// Produces the type of the current object but no subobjects.
     57        const Type * getCurrentType();
     58};
    5959
    60 namespace ast {
    61         // AST class types
    62         class Designation;
    63         struct InitAlternative;
    64         class Type;
    65 
    66         /// Iterates members of a type by initializer
    67         class MemberIterator;
    68 
    69         /// Builds initializer lists in resolution
    70         class CurrentObject final {
    71                 std::vector< std::shared_ptr<MemberIterator> > objStack;
    72        
    73         public:
    74                 CurrentObject() = default;
    75                 CurrentObject( const CodeLocation & loc, const Type * type );
    76 
    77                 /// resolves unresolved designation
    78                 const Designation * findNext( const Designation * designation );
    79                 /// sets current position using the resolved designation
    80                 void setNext( const ast::Designation * designation );
    81                 /// steps to next sub-object of current object
    82                 void increment();
    83                 /// sets new current object for the duration of this brace-enclosed intializer-list
    84                 void enterListInit( const CodeLocation & loc );
    85                 /// restores previous current object
    86                 void exitListInit();
    87                 /// produces a list of alternatives (Type *, Designation *) for the current sub-object's
    88                 /// initializer.
    89                 std::deque< InitAlternative > getOptions();
    90                 /// produces the type of the current object but no subobjects
    91                 const Type * getCurrentType();
    92         };
    9360} // namespace ast
    9461
  • src/ResolvExpr/FindOpenVars.cc

    r16e0dcb rf7f997a  
    2424namespace ResolvExpr {
    2525
    26         namespace {
    27                 struct FindOpenVars final : public ast::WithGuards {
    28                         ast::OpenVarSet & open;
    29                         ast::OpenVarSet & closed;
    30                         ast::AssertionSet & need;
    31                         ast::AssertionSet & have;
    32                         ast::TypeEnvironment & env;
    33                         bool nextIsOpen;
     26namespace {
    3427
    35                         FindOpenVars(
    36                                 ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n,
    37                                 ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen )
    38                         : open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {}
     28struct FindOpenVars final : public ast::WithGuards {
     29        ast::OpenVarSet & open;
     30        ast::OpenVarSet & closed;
     31        ast::AssertionSet & need;
     32        ast::AssertionSet & have;
     33        ast::TypeEnvironment & env;
     34        bool nextIsOpen;
    3935
    40                         void previsit( const ast::FunctionType * type ) {
    41                                 // mark open/closed variables
    42                                 if ( nextIsOpen ) {
    43                                         // trying to remove this from resolver.
    44                                         // occasionally used in other parts so not deleting right now.
     36        FindOpenVars(
     37                ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n,
     38                ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen )
     39        : open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {}
    4540
    46                                         // insert open variables unbound to environment.
    47                                         env.add(type->forall);
     41        void previsit( const ast::FunctionType * type ) {
     42                // mark open/closed variables
     43                if ( nextIsOpen ) {
     44                        // trying to remove this from resolver.
     45                        // occasionally used in other parts so not deleting right now.
    4846
    49                                         for ( auto & decl : type->forall ) {
    50                                                 open[ *decl ] = ast::TypeData{ decl->base };
    51                                         }
    52                                         for ( auto & assert : type->assertions ) {
    53                                                 need[ assert ].isUsed = false;
    54                                         }
    55                                 } else {
    56                                         for ( auto & decl : type->forall ) {
    57                                                 closed[ *decl ] = ast::TypeData{ decl->base };
    58                                         }
    59                                         for ( auto & assert : type->assertions ) {
    60                                                 have[ assert ].isUsed = false;
    61                                         }
    62                                 }
     47                        // insert open variables unbound to environment.
     48                        env.add(type->forall);
    6349
    64                                 // flip open variables for contained function types
    65                                 nextIsOpen = ! nextIsOpen;
    66                                 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
     50                        for ( auto & decl : type->forall ) {
     51                                open[ *decl ] = ast::TypeData{ decl->base };
    6752                        }
     53                        for ( auto & assert : type->assertions ) {
     54                                need[ assert ].isUsed = false;
     55                        }
     56                } else {
     57                        for ( auto & decl : type->forall ) {
     58                                closed[ *decl ] = ast::TypeData{ decl->base };
     59                        }
     60                        for ( auto & assert : type->assertions ) {
     61                                have[ assert ].isUsed = false;
     62                        }
     63                }
    6864
    69                 };
     65                // flip open variables for contained function types
     66        //      nextIsOpen = ! nextIsOpen;
     67        //      GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
     68                GuardValue( nextIsOpen ) = !nextIsOpen;
    7069        }
     70};
    7171
    72         void findOpenVars(
    73                         const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
    74                         ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) {
    75                 ast::Pass< FindOpenVars > finder{ open, closed, need, have, env, firstIsOpen };
    76                 type->accept( finder );
     72} // namespace
    7773
    78                 if (!closed.empty()) {
    79                         std::cerr << "closed: ";
    80                         for (auto& i : closed) {
    81                                 std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';
    82                         }
    83                         std::cerr << std::endl;
     74void findOpenVars(
     75                const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
     76                ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) {
     77        ast::Pass< FindOpenVars > finder{ open, closed, need, have, env, firstIsOpen };
     78        type->accept( finder );
     79
     80        if (!closed.empty()) {
     81                std::cerr << "closed: ";
     82                for (auto& i : closed) {
     83                        std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';
    8484                }
     85                std::cerr << std::endl;
    8586        }
     87}
     88
    8689} // namespace ResolvExpr
    8790
  • src/ResolvExpr/FindOpenVars.h

    r16e0dcb rf7f997a  
    2323
    2424namespace ResolvExpr {
    25         enum FirstMode { FirstClosed, FirstOpen };
    2625
    27         // Updates open and closed variables and their associated assertions
    28         void findOpenVars(
    29                 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
    30                 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen );
     26enum FirstMode { FirstClosed, FirstOpen };
     27
     28// Updates open and closed variables and their associated assertions
     29void findOpenVars(
     30        const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
     31        ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen );
     32
    3133} // namespace ResolvExpr
    3234
  • src/ResolvExpr/PolyCost.cc

    r16e0dcb rf7f997a  
    2020
    2121namespace ResolvExpr {
     22
     23namespace {
    2224
    2325class PolyCost {
     
    4547};
    4648
     49} // namespace
     50
    4751int polyCost(
    4852        const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
  • src/ResolvExpr/PtrsAssignable.cc

    r16e0dcb rf7f997a  
    2121
    2222namespace ResolvExpr {
     23
     24namespace {
    2325
    2426struct PtrsAssignable : public ast::WithShortCircuiting {
     
    5153        }
    5254};
     55
     56} // namespace
    5357
    5458int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
  • src/ResolvExpr/RenameVars.h

    r16e0dcb rf7f997a  
    2121
    2222namespace ResolvExpr {
    23         enum RenameMode {
    24                 GEN_USAGE, // for type in VariableExpr
    25                 GEN_EXPR_ID // for type in decl
    26         };
    27         const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );
    2823
    29         /// resets internal state of renamer to avoid overflow
    30         void resetTyVarRenaming();
     24enum RenameMode {
     25        GEN_USAGE, // for type in VariableExpr
     26        GEN_EXPR_ID // for type in decl
     27};
     28const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );
     29
     30/// Resets internal state of renamer to avoid overflow.
     31void resetTyVarRenaming();
     32
    3133} // namespace ResolvExpr
    3234
  • src/ResolvExpr/ResolvMode.h

    r16e0dcb rf7f997a  
    1717
    1818namespace ResolvExpr {
    19         /// Flag set for resolution
    20         struct ResolvMode {
    21                 const bool adjust;                       ///< Adjust array and function types to pointer types? [false]
    22                 const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
    23                 const bool failFast;         ///< Fail on no resulting alternatives? [true]
    2419
    25                 constexpr ResolvMode(bool a, bool p, bool ff)
    26                 : adjust(a), prune(p), failFast(ff) {}
     20/// Flag set for resolution
     21struct ResolvMode {
     22        const bool adjust;                       ///< Adjust array and function types to pointer types? [false]
     23        const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
     24        const bool failFast;         ///< Fail on no resulting alternatives? [true]
    2725
    28                 /// Default settings
    29                 constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
    30                
    31                 /// With adjust flag set; turns array and function types into equivalent pointers
    32                 static constexpr ResolvMode withAdjustment() { return { true, true, true }; }
     26        constexpr ResolvMode(bool a, bool p, bool ff)
     27        : adjust(a), prune(p), failFast(ff) {}
    3328
    34                 /// With adjust flag set but prune unset; pruning ensures there is at least one alternative
    35                 /// per result type
    36                 static constexpr ResolvMode withoutPrune() { return { true, false, true }; }
     29        /// Default settings
     30        constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
    3731
    38                 /// With adjust and prune flags set but failFast unset; failFast ensures there is at least
    39                 /// one resulting alternative
    40                 static constexpr ResolvMode withoutFailFast() { return { true, true, false }; }
     32        /// With adjust flag set; turns array and function types into equivalent pointers
     33        static constexpr ResolvMode withAdjustment() { return { true, true, true }; }
    4134
    42                 /// The same mode, but with satisfyAssns turned on; for top-level calls
    43                 ResolvMode atTopLevel() const { return { adjust, true, failFast }; }
    44         };
     35        /// With adjust flag set but prune unset; pruning ensures there is at least one alternative
     36        /// per result type
     37        static constexpr ResolvMode withoutPrune() { return { true, false, true }; }
     38
     39        /// With adjust and prune flags set but failFast unset; failFast ensures there is at least
     40        /// one resulting alternative
     41        static constexpr ResolvMode withoutFailFast() { return { true, true, false }; }
     42
     43        /// The same mode, but with satisfyAssns turned on; for top-level calls
     44        ResolvMode atTopLevel() const { return { adjust, true, failFast }; }
     45};
     46
    4547} // namespace ResolvExpr
    4648
  • src/ResolvExpr/ResolveTypeof.cc

    r16e0dcb rf7f997a  
    3333
    3434namespace {
     35
    3536struct ResolveTypeof : public ast::WithShortCircuiting {
    3637    const ResolveContext & context;
     
    7576    }
    7677};
     78
    7779} // anonymous namespace
    7880
  • src/ResolvExpr/ResolveTypeof.h

    r16e0dcb rf7f997a  
    2222
    2323namespace ResolvExpr {
    24         struct ResolveContext;
    2524
    26         const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
    27         const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
    28         const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
    29         const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & );
     25struct ResolveContext;
     26
     27const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
     28const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
     29const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
     30const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & );
     31
    3032} // namespace ResolvExpr
    3133
  • src/ResolvExpr/Resolver.h

    r16e0dcb rf7f997a  
    3434namespace ResolvExpr {
    3535
    36         /// Helper Type: Passes around information between various sub-calls.
    37         struct ResolveContext {
    38                 const ast::SymbolTable & symtab;
    39                 const ast::TranslationGlobal & global;
    40         };
     36/// Helper Type: Passes around information between various sub-calls.
     37struct ResolveContext {
     38        const ast::SymbolTable & symtab;
     39        const ast::TranslationGlobal & global;
     40};
    4141
    42         /// Checks types and binds syntactic constructs to typed representations
    43         void resolve( ast::TranslationUnit& translationUnit );
    44         /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
    45         const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
    46         /// Find the expression candidate that is the unique best match for `untyped` in a `void`
    47         /// context.
    48         ast::ptr< ast::Expr > resolveInVoidContext(
    49                 const ast::Expr * expr, const ResolveContext &, ast::TypeEnvironment & env );
    50         /// Resolve `untyped` to the single expression whose candidate is the best match for the
    51         /// given type.
    52         ast::ptr< ast::Expr > findSingleExpression(
    53                 const ast::Expr * untyped, const ast::Type * type, const ResolveContext & );
    54         ast::ptr< ast::Expr > findVoidExpression(
    55                 const ast::Expr * untyped, const ResolveContext & );
    56         /// Resolves a constructor init expression
    57         ast::ptr< ast::Init > resolveCtorInit(
    58                 const ast::ConstructorInit * ctorInit, const ResolveContext & context );
    59         /// Resolves a statement expression
    60         const ast::Expr * resolveStmtExpr(
    61                 const ast::StmtExpr * stmtExpr, const ResolveContext & context );
     42/// Checks types and binds syntactic constructs to typed representations
     43void resolve( ast::TranslationUnit& translationUnit );
     44/// Searches expr and returns the first DeletedExpr found, otherwise nullptr
     45const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
     46/// Find the expression candidate that is the unique
     47/// best match for `untyped` in a `void` context.
     48ast::ptr< ast::Expr > resolveInVoidContext(
     49        const ast::Expr * expr, const ResolveContext &, ast::TypeEnvironment & env );
     50/// Resolve `untyped` to the single expression whose
     51/// candidate is the best match for the given type.
     52ast::ptr< ast::Expr > findSingleExpression(
     53        const ast::Expr * untyped, const ast::Type * type, const ResolveContext & );
     54ast::ptr< ast::Expr > findVoidExpression(
     55        const ast::Expr * untyped, const ResolveContext & );
     56/// Resolves a constructor init expression
     57ast::ptr< ast::Init > resolveCtorInit(
     58        const ast::ConstructorInit * ctorInit, const ResolveContext & context );
     59/// Resolves a statement expression
     60const ast::Expr * resolveStmtExpr(
     61        const ast::StmtExpr * stmtExpr, const ResolveContext & context );
     62
    6263} // namespace ResolvExpr
    6364
  • src/ResolvExpr/SatisfyAssertions.cpp

    r16e0dcb rf7f997a  
    473473                                                errors.emplace_back( ss.str() );
    474474                                                goto nextSat;
    475                                         }
    476                                         else if ( result == AssertionResult::Skip ) {
     475                                        } else if ( result == AssertionResult::Skip ) {
    477476                                                next.emplace_back(assn);
    478477                                                // goto nextSat;
  • src/ResolvExpr/SpecCost.cc

    r16e0dcb rf7f997a  
    3333}
    3434
    35         /// The specialization counter inner class.
    36         class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> {
    37                 int count = -1;  ///< specialization count (-1 for none)
     35/// The specialization counter inner class.
     36class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> {
     37        int count = -1;  ///< specialization count (-1 for none)
    3838
    39                 // Converts the max value to -1 (none), otherwise increments the value.
    40                 static int toNoneOrInc( int value ) {
    41                         assert( 0 <= value );
    42                         return value < std::numeric_limits<int>::max() ? value + 1 : -1;
     39        // Converts the max value to -1 (none), otherwise increments the value.
     40        static int toNoneOrInc( int value ) {
     41                assert( 0 <= value );
     42                return value < std::numeric_limits<int>::max() ? value + 1 : -1;
     43        }
     44
     45        template<typename T> using MapperT =
     46                typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
     47
     48        // Update the minimum to the new lowest non-none value.
     49        template<typename T>
     50        void updateMinimumPresent( int & minimum, const T & list, MapperT<T> mapper ) {
     51                for ( const auto & node : list ) {
     52                        count = -1;
     53
     54                        if ( ast::Type const * type = mapper( node ) ) {
     55                                ast::Type const * newType = type->accept( *visitor );
     56                                assert( newType == nullptr || newType == type );
     57                        }
     58
     59                        if ( count != -1 && count < minimum ) minimum = count;
    4360                }
     61        }
    4462
    45                 template<typename T> using MapperT =
    46                         typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
     63        // Returns minimum non-negative count + 1 over type parameters (-1 if none such).
     64        template<typename T>
     65        int minimumPresent( const T & list, MapperT<T> mapper ) {
     66                int minCount = std::numeric_limits<int>::max();
     67                updateMinimumPresent( minCount, list, mapper );
     68                return toNoneOrInc( minCount );
     69        }
    4770
    48                 // Update the minimum to the new lowest non-none value.
    49                 template<typename T>
    50                 void updateMinimumPresent( int & minimum, const T & list, MapperT<T> mapper ) {
    51                         for ( const auto & node : list ) {
    52                                 count = -1;
     71public:
     72        int result() const { return 0 <= count ? count : 0; }
    5373
    54                                 if ( ast::Type const * type = mapper( node ) ) {
    55                                         ast::Type const * newType = type->accept( *visitor );
    56                                         assert( newType == nullptr || newType == type );
    57                                 }
     74        // Mark specialization of base type.
     75        void postvisit( const ast::PointerType * ) { if ( 0 <= count ) ++count; }
     76        void postvisit( const ast::ArrayType * ) { if ( 0 <= count ) ++count; }
     77        void postvisit( const ast::ReferenceType * ) { if ( 0 <= count ) ++count; }
    5878
    59                                 if ( count != -1 && count < minimum ) minimum = count;
    60                         }
    61                 }
     79        void postvisit( const ast::StructInstType * ) { if ( 0 <= count ) ++count; }
     80        void postvisit( const ast::UnionInstType * ) { if ( 0 <= count ) ++count; }
    6281
    63                 // Returns minimum non-negative count + 1 over type parameters (-1 if none such).
    64                 template<typename T>
    65                 int minimumPresent( const T & list, MapperT<T> mapper ) {
    66                         int minCount = std::numeric_limits<int>::max();
    67                         updateMinimumPresent( minCount, list, mapper );
    68                         return toNoneOrInc( minCount );
    69                 }
     82        // Use the minimal specialization value over returns and params.
     83        void previsit( const ast::FunctionType * fty ) {
     84                int minCount = std::numeric_limits<int>::max();
     85                updateMinimumPresent( minCount, fty->params, type_deref );
     86                updateMinimumPresent( minCount, fty->returns, type_deref );
     87                // Add another level to minCount if set.
     88                count = toNoneOrInc( minCount );
     89                // We have already visited children.
     90                visit_children = false;
     91        }
    7092
    71         public:
    72                 int result() const { return 0 <= count ? count : 0; }
     93        // Look for polymorphic parameters.
     94        void previsit( const ast::StructInstType * sty ) {
     95                count = minimumPresent( sty->params, expr_result );
     96        }
    7397
    74                 // Mark specialization of base type.
    75                 void postvisit( const ast::PointerType * ) { if ( count >= 0 ) ++count; }
    76                 void postvisit( const ast::ArrayType * ) { if ( count >= 0 ) ++count; }
    77                 void postvisit( const ast::ReferenceType * ) { if ( count >= 0 ) ++count; }
     98        // Look for polymorphic parameters.
     99        void previsit( const ast::UnionInstType * uty ) {
     100                count = minimumPresent( uty->params, expr_result );
     101        }
    78102
    79                 void postvisit( const ast::StructInstType * ) { if ( count >= 0 ) ++count; }
    80                 void postvisit( const ast::UnionInstType * ) { if ( count >= 0 ) ++count; }
     103        // Note polymorphic type (which may be specialized).
     104        // xxx - maybe account for open/closed type variables
     105        void postvisit( const ast::TypeInstType * ) { count = 0; }
    81106
    82                 // Use the minimal specialization value over returns and params.
    83                 void previsit( const ast::FunctionType * fty ) {
    84                         int minCount = std::numeric_limits<int>::max();
    85                         updateMinimumPresent( minCount, fty->params, type_deref );
    86                         updateMinimumPresent( minCount, fty->returns, type_deref );
    87                         // Add another level to minCount if set.
    88                         count = toNoneOrInc( minCount );
    89                         // We have already visited children.
    90                         visit_children = false;
    91                 }
    92 
    93                 // Look for polymorphic parameters.
    94                 void previsit( const ast::StructInstType * sty ) {
    95                         count = minimumPresent( sty->params, expr_result );
    96                 }
    97 
    98                 // Look for polymorphic parameters.
    99                 void previsit( const ast::UnionInstType * uty ) {
    100                         count = minimumPresent( uty->params, expr_result );
    101                 }
    102 
    103                 // Note polymorphic type (which may be specialized).
    104                 // xxx - maybe account for open/closed type variables
    105                 void postvisit( const ast::TypeInstType * ) { count = 0; }
    106 
    107                 // Use the minimal specialization over elements.
    108                 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
    109                 void previsit( const ast::TupleType * tty ) {
    110                         count = minimumPresent( tty->types, type_deref );
    111                         visit_children = false;
    112                 }
    113         };
     107        // Use the minimal specialization over elements.
     108        // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
     109        void previsit( const ast::TupleType * tty ) {
     110                count = minimumPresent( tty->types, type_deref );
     111                visit_children = false;
     112        }
     113};
    114114
    115115} // namespace
  • src/ResolvExpr/SpecCost.hpp

    r16e0dcb rf7f997a  
    1616#pragma once
    1717
    18 class Type;
    1918namespace ast {
    2019    class Type;
     
    2322namespace ResolvExpr {
    2423
    25 int specCost( Type * type );
    2624int specCost( const ast::Type * type );
    2725
  • src/ResolvExpr/Unify.cc

    r16e0dcb rf7f997a  
    537537                        // assert( open.find( *typeInst ) == open.end() );
    538538                        auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
    539                         if (otherInst && typeInst->name == otherInst->name)
     539                        if ( otherInst && typeInst->name == otherInst->name ) {
    540540                                this->result = otherInst;
    541                         // return otherInst;
     541                        }
    542542                }
    543543
     
    628628                        result = dynamic_cast< const ast::OneType * >( type2 );
    629629                }
    630 
    631           private:
    632                 template< typename RefType > void handleRefType( RefType *inst, Type *other );
    633                 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
    634630        };
    635631
  • src/ResolvExpr/Unify.h

    r16e0dcb rf7f997a  
    1515
    1616#pragma once
    17 
    18 #include <list>                   // for list
    1917
    2018#include "AST/Node.hpp"             // for ptr
     
    4745        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    4846        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    49         const ast::OpenVarSet & open, WidenMode widen, 
     47        const ast::OpenVarSet & open, WidenMode widen,
    5048        ast::ptr<ast::Type> & common );
    5149
    5250bool typesCompatible(
    53         const ast::Type *, const ast::Type *, 
     51        const ast::Type *, const ast::Type *,
    5452        const ast::TypeEnvironment & env = {} );
    5553
  • src/ResolvExpr/WidenMode.h

    r16e0dcb rf7f997a  
    1717
    1818namespace ResolvExpr {
    19         struct WidenMode {
    20                 WidenMode( bool first, bool second ): first( first ), second( second ) {}
    2119
    22                 WidenMode &operator|=( const WidenMode &other ) {
    23                         first |= other.first; second |= other.second; return *this;
    24                 }
     20struct WidenMode {
     21        WidenMode( bool first, bool second ): first( first ), second( second ) {}
    2522
    26                 WidenMode &operator&=( const WidenMode &other ) {
    27                         first &= other.first; second &= other.second; return *this;
    28                 }
     23        WidenMode &operator|=( const WidenMode &other ) {
     24                first |= other.first; second |= other.second; return *this;
     25        }
    2926
    30                 WidenMode operator|( const WidenMode &other ) {
    31                         WidenMode newWM( *this ); newWM |= other; return newWM;
    32                 }
     27        WidenMode &operator&=( const WidenMode &other ) {
     28                first &= other.first; second &= other.second; return *this;
     29        }
    3330
    34                 WidenMode operator&( const WidenMode &other ) {
    35                         WidenMode newWM( *this ); newWM &= other; return newWM;
    36                 }
     31        WidenMode operator|( const WidenMode &other ) {
     32                WidenMode newWM( *this ); newWM |= other; return newWM;
     33        }
    3734
    38                 operator bool() { return first && second; }
     35        WidenMode operator&( const WidenMode &other ) {
     36                WidenMode newWM( *this ); newWM &= other; return newWM;
     37        }
    3938
    40                 bool first : 1, second : 1;
    41         };
     39        operator bool() { return first && second; }
    4240
    43         static inline WidenMode noWiden() { return { false, false }; }
     41        bool first : 1, second : 1;
     42};
     43
     44static inline WidenMode noWiden() { return { false, false }; }
     45
    4446} // namespace ResolvExpr
    4547
  • tests/exceptions/.expect/cardgame.x86.txt

    r16e0dcb rf7f997a  
    11start
    2 20
    3 37
    4 23
    5 7
    621
    7 115
    8 115
    930
    10 62
    11 8
    12 41
    13 4294967295
     41
     52
     61
     73
     81
     91
    14100
    15 92
    16 134
    17 8
    18 67
    19 23
    20 27
    21 138
    22 133
     112
     121
     135
     140
    23154
    24 59
    25 79
    26 122
    27 23
    28 5
     160
    29172
    30 33
    31 15
    32 106
     181
    33190
    34 14
    35 90
    36 4294967295
    37 81
    38 39
    39 4294967295
    40 36
    41 116
    42 160
    43 76
    44 127
    45 4
    46 29
    47 6
    48 12
    49 9
    50 18
    51203
    5221done
Note: See TracChangeset for help on using the changeset viewer.