Changeset 2908f08


Ignore:
Timestamp:
Nov 17, 2023, 3:03:51 PM (6 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
f7f997a
Parents:
41606df1
Message:

Most of ResolvExpr? was written before the new style standard. Some files updated, focus on headers.

Location:
src/ResolvExpr
Files:
21 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/AdjustExprType.cc

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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

    r41606df1 r2908f08  
    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
Note: See TracChangeset for help on using the changeset viewer.