Changes in / [f7f997a:16e0dcb]


Ignore:
Files:
22 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/AdjustExprType.cc

    rf7f997a r16e0dcb  
    2323
    2424namespace {
     25        class AdjustExprType final : public ast::WithShortCircuiting {
     26                const ast::SymbolTable & symtab;
     27        public:
     28                const ast::TypeEnvironment & tenv;
    2529
    26 class AdjustExprType final : public ast::WithShortCircuiting {
    27         const ast::SymbolTable & symtab;
    28 public:
    29         const ast::TypeEnvironment & tenv;
     30                AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
     31                : symtab( syms ), tenv( e ) {}
    3032
    31         AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    32         : symtab( syms ), tenv( e ) {}
     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; }
    3347
    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; }
     48                const ast::Type * postvisit( const ast::ArrayType * at ) {
     49                        return new ast::PointerType{ at->base, at->qualifiers };
     50                }
    4851
    49         const ast::Type * postvisit( const ast::ArrayType * at ) {
    50                 return new ast::PointerType( at->base, at->qualifiers );
    51         }
     52                const ast::Type * postvisit( const ast::FunctionType * ft ) {
     53                        return new ast::PointerType{ ft };
     54                }
    5255
    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 );
     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                                        }
    6767                                }
    6868                        }
     69                        return inst;
    6970                }
    70                 return inst;
    71         }
    72 };
    73 
     71        };
    7472} // anonymous namespace
    7573
  • src/ResolvExpr/CandidateFinder.cpp

    rf7f997a r16e0dcb  
    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                         } else {
    760                                 if ( !unify(
     759                        }
     760                        else {
     761                                if ( ! unify(
    761762                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen )
    762763                                ) {
     
    11081109                                                intrinsicResult.emplace_back(std::move(withFunc));
    11091110                                        }
    1110                                 } else {
     1111                                }
     1112                                else {
    11111113                                        candidates.emplace_back( std::move( withFunc ) );
    11121114                                }
     
    11541156
    11551157                for ( CandidateRef & r : finder.candidates ) {
    1156                         if ( !isLvalue( r->expr ) ) continue;
     1158                        if ( ! isLvalue( r->expr ) ) continue;
    11571159                        addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
    11581160                }
  • src/ResolvExpr/CommonType.cc

    rf7f997a r16e0dcb  
    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 };
    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 };
    398                                 }
    399                         }
    400                 }
    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
     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 };
     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 };
     398                                        }
     399                                }
     400                        }
     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
    425425                                && unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen)) {
    426426                                        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                                 } 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 
    478                                         if (
    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()))) {
     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() ) ) {
    578463                                                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;
     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;
    592469                                                }
    593470                                        }
    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;
     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 );
     610                        } 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                                                }
    639651                                        }
    640652                                }
    641                         }
    642                 } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
    643                         result = ref;
    644                         add_qualifiers( result, type2->qualifiers );
    645                 } else {
     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 ) {
    646675                        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 )
     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 )
    681692                                || 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 );
    694                         } else {
    695693                                if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
    696694                                        result = type2;
    697695                                        add_qualifiers( result, zero->qualifiers );
    698696                                }
    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 {
     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 ) ) {
    719717                                if ( widen.second || one->qualifiers <= type2->qualifiers ) {
    720718                                        result = type2;
    721719                                        add_qualifiers( result, one->qualifiers );
    722720                                }
    723                         }
     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;
     754                                PRINT(
     755                                        std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
     756                                )
     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
     766                        PRINT(
     767                                std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
     768                        )
     769                        return { nullptr };
    724770                }
    725771        }
    726 };
    727 
    728 // size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
    729 
    730 namespace {
    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
     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
    735777        ) {
    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;
     778                unsigned depth1 = type1->referenceDepth();
     779                unsigned depth2 = type2->referenceDepth();
     780
     781                if ( depth1 != depth2 ) {  // implies depth1 > 0 || depth2 > 0
    743782                        PRINT(
    744                                 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
     783                                std::cerr << "reference depth diff: " << (depth1-depth2) << std::endl;
    745784                        )
    746                         if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
     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
    747799                                PRINT(
    748                                         std::cerr << "widen okay" << std::endl;
     800                                        std::cerr << "formal is reference; result should be reference" << std::endl;
    749801                                )
    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 };
     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;
    759817        }
    760 }
    761 
    762 ast::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
    788                         PRINT(
    789                                 std::cerr << "formal is reference; result should be reference" << std::endl;
    790                         )
    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 }
    807818
    808819} // namespace ResolvExpr
  • src/ResolvExpr/Cost.h

    rf7f997a r16e0dcb  
    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.
    2325
    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        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;
     44                };
     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                }; //'
    2660
    27 class 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;
     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                }
     79
     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; }
     87
     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 );
     97
     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
     107                        return *this;
     108                }
     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 );
    45146        };
    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         }; //'
    61147
    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
    78                 };
     148        inline bool operator==( const Cost lhs, const Cost rhs ) {
     149                return lhs.all == rhs.all;
    79150        }
    80151
    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; }
    88 
    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 );
    98 
    99         friend Cost operator+( const Cost lhs, const Cost rhs );
    100 
    101         Cost operator+=( const Cost rhs ) {
    102                 if ( all == infinity ) return *this;
    103                 if ( rhs.all == infinity ) {
    104                         all = infinity;
    105                         return *this;
    106                 }
    107                 all += rhs.all - correctw;                                      // correct for negative spec cost
    108                 return *this;
     152        inline bool operator!=( const Cost lhs, const Cost rhs ) {
     153                return !( lhs.all == rhs.all );
    109154        }
    110155
    111         Cost incUnsafe( int inc = 1 ) {
    112                 if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; }
    113                 return *this;
     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;
    114160        }
    115161
    116         Cost incPoly( int inc = 1 ) {
    117                 if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; }
    118                 return *this;
     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
    119165        }
    120166
    121         Cost incSafe( int inc = 1 ) {
    122                 if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; }
    123                 return *this;
     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() << " )";
    124171        }
    125 
    126         Cost incSign( int inc = 1 ) {
    127                 if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; }
    128                 return *this;
    129         }
    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 
    149 inline bool operator==( const Cost lhs, const Cost rhs ) {
    150         return lhs.all == rhs.all;
    151 }
    152 
    153 inline bool operator!=( const Cost lhs, const Cost rhs ) {
    154         return !( lhs.all == rhs.all );
    155 }
    156 
    157 inline 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 
    163 inline 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 
    168 inline 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 
    174172} // namespace ResolvExpr
    175173
  • src/ResolvExpr/CurrentObject.cc

    rf7f997a r16e0dcb  
    4141
    4242namespace ast {
    43 
    44 /// Iterates members of a type by initializer.
    45 class MemberIterator {
    46 public:
    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 
    83 namespace {
    84 
    85 /// create a new MemberIterator that traverses a type correctly
    86 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
    87 
    88 /// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry
    89 class SimpleIterator final : public MemberIterator {
    90         CodeLocation location;
    91         const Type * type = nullptr;
    92 public:
    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:
    125 class IndexIterator : public MemberIterator {
    126 protected:
    127         CodeLocation location;
    128         size_t index = 0;
    129         size_t size = 0;
    130         std::unique_ptr<MemberIterator> memberIter;
    131 public:
    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:
    176 class 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 
    188 public:
    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 ) );
     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 } );
    229353                        }
    230354                        return ret;
    231355                }
    232                 return {};
    233         }
    234 };
    235 
    236 class AggregateIterator : public MemberIterator {
    237 protected:
    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 
    273 public:
    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() );
     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 };
    293476                } 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 
    361 class StructIterator final : public AggregateIterator {
    362 public:
    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 
    383 class UnionIterator final : public AggregateIterator {
    384 public:
    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:
    402 class 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 
    410 public:
    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 
    459 MemberIterator * 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() );
    473477                        return new SimpleIterator{ loc, type };
    474478                }
    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 
    486 CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() {
    487         objStack.emplace_back( new SimpleIterator{ loc, type } );
    488 }
    489 
    490 const 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 );
     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                                                        }
    515521                                                }
    516522                                        }
    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                                                 }
     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 );
    526531                                        }
    527532                                }
    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;
     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;
     572                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        }
    566605}
    567 
    568 void 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 
    574 void 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 
    581 void 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 
    589 void 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() ) {
    594                 PRINT( std::cerr << *objStack.back() << std::endl; )
    595                 objStack.back()->bigStep();
    596         }
    597 }
    598 
    599 std::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 
    605 const 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
    612606
    613607// Local Variables: //
  • src/ResolvExpr/CurrentObject.h

    rf7f997a r16e0dcb  
    1717
    1818#include <deque>
     19#include <list>   // for list
    1920#include <memory> // for unique_ptr
     21#include <stack>  // for stack
    2022#include <vector>
    2123
     
    2325#include "Common/CodeLocation.h"
    2426
    25 namespace ast {
    26 
    27 // AST class types:
    2827class Designation;
    2928class Type;
    3029struct InitAlternative;
    3130
    32 /// Iterates members of a type by initializer
    33 class MemberIterator;
     31namespace ResolvExpr {
     32        class MemberIterator;
    3433
    35 /// Builds initializer lists in resolution
    36 class CurrentObject final {
    37         std::vector<std::shared_ptr<MemberIterator>> objStack;
     34        // TODO: memory management of MemberIterators
     35        class CurrentObject {
     36        public:
     37                CurrentObject();
     38                CurrentObject( Type * type );
    3839
    39 public:
    40         CurrentObject() = default;
    41         CurrentObject( const CodeLocation & loc, const Type * type );
     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();
    4254
    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 };
     55        private:
     56                std::stack< MemberIterator * > objStack;
     57        };
     58} // namespace ResolvExpr
    5959
     60namespace 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        };
    6093} // namespace ast
    6194
  • src/ResolvExpr/FindOpenVars.cc

    rf7f997a r16e0dcb  
    2424namespace ResolvExpr {
    2525
    26 namespace {
     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;
    2734
    28 struct 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;
     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 ) {}
    3539
    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 ) {}
     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.
    4045
    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.
     46                                        // insert open variables unbound to environment.
     47                                        env.add(type->forall);
    4648
    47                         // insert open variables unbound to environment.
    48                         env.add(type->forall);
     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                                }
    4963
    50                         for ( auto & decl : type->forall ) {
    51                                 open[ *decl ] = ast::TypeData{ decl->base };
     64                                // flip open variables for contained function types
     65                                nextIsOpen = ! nextIsOpen;
     66                                GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
    5267                        }
    53                         for ( auto & assert : type->assertions ) {
    54                                 need[ assert ].isUsed = false;
     68
     69                };
     70        }
     71
     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 );
     77
     78                if (!closed.empty()) {
     79                        std::cerr << "closed: ";
     80                        for (auto& i : closed) {
     81                                std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';
    5582                        }
    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                         }
     83                        std::cerr << std::endl;
    6384                }
    64 
    65                 // flip open variables for contained function types
    66         //      nextIsOpen = ! nextIsOpen;
    67         //      GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
    68                 GuardValue( nextIsOpen ) = !nextIsOpen;
    6985        }
    70 };
    71 
    72 } // namespace
    73 
    74 void 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 << ' ';
    84                 }
    85                 std::cerr << std::endl;
    86         }
    87 }
    88 
    8986} // namespace ResolvExpr
    9087
  • src/ResolvExpr/FindOpenVars.h

    rf7f997a r16e0dcb  
    2323
    2424namespace ResolvExpr {
     25        enum FirstMode { FirstClosed, FirstOpen };
    2526
    26 enum FirstMode { FirstClosed, FirstOpen };
    27 
    28 // Updates open and closed variables and their associated assertions
    29 void 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 
     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 );
    3331} // namespace ResolvExpr
    3432
  • src/ResolvExpr/PolyCost.cc

    rf7f997a r16e0dcb  
    2020
    2121namespace ResolvExpr {
    22 
    23 namespace {
    2422
    2523class PolyCost {
     
    4745};
    4846
    49 } // namespace
    50 
    5147int polyCost(
    5248        const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
  • src/ResolvExpr/PtrsAssignable.cc

    rf7f997a r16e0dcb  
    2121
    2222namespace ResolvExpr {
    23 
    24 namespace {
    2523
    2624struct PtrsAssignable : public ast::WithShortCircuiting {
     
    5351        }
    5452};
    55 
    56 } // namespace
    5753
    5854int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
  • src/ResolvExpr/RenameVars.h

    rf7f997a r16e0dcb  
    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 );
    2328
    24 enum RenameMode {
    25         GEN_USAGE, // for type in VariableExpr
    26         GEN_EXPR_ID // for type in decl
    27 };
    28 const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );
    29 
    30 /// Resets internal state of renamer to avoid overflow.
    31 void resetTyVarRenaming();
    32 
     29        /// resets internal state of renamer to avoid overflow
     30        void resetTyVarRenaming();
    3331} // namespace ResolvExpr
    3432
  • src/ResolvExpr/ResolvMode.h

    rf7f997a r16e0dcb  
    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]
    1924
    20 /// Flag set for resolution
    21 struct 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]
     25                constexpr ResolvMode(bool a, bool p, bool ff)
     26                : adjust(a), prune(p), failFast(ff) {}
    2527
    26         constexpr ResolvMode(bool a, bool p, bool ff)
    27         : adjust(a), prune(p), failFast(ff) {}
     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 }; }
    2833
    29         /// Default settings
    30         constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
     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 }; }
    3137
    32         /// With adjust flag set; turns array and function types into equivalent pointers
    33         static constexpr ResolvMode withAdjustment() { return { true, true, true }; }
     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 }; }
    3441
    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 
     42                /// The same mode, but with satisfyAssns turned on; for top-level calls
     43                ResolvMode atTopLevel() const { return { adjust, true, failFast }; }
     44        };
    4745} // namespace ResolvExpr
    4846
  • src/ResolvExpr/ResolveTypeof.cc

    rf7f997a r16e0dcb  
    3333
    3434namespace {
    35 
    3635struct ResolveTypeof : public ast::WithShortCircuiting {
    3736    const ResolveContext & context;
     
    7675    }
    7776};
    78 
    7977} // anonymous namespace
    8078
  • src/ResolvExpr/ResolveTypeof.h

    rf7f997a r16e0dcb  
    2222
    2323namespace ResolvExpr {
     24        struct ResolveContext;
    2425
    25 struct ResolveContext;
    26 
    27 const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
    28 const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
    29 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
    30 const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & );
    31 
     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 & );
    3230} // namespace ResolvExpr
    3331
  • src/ResolvExpr/Resolver.h

    rf7f997a r16e0dcb  
    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.
     37        struct 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
    47 /// best match for `untyped` in a `void` 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
    51 /// candidate is the best match for the 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 );
    62 
     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 );
    6362} // namespace ResolvExpr
    6463
  • src/ResolvExpr/SatisfyAssertions.cpp

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

    rf7f997a r16e0dcb  
    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.
     36        class 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;
    43         }
     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                }
    4444
    45         template<typename T> using MapperT =
    46                 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
     45                template<typename T> using MapperT =
     46                        typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
    4747
    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;
     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;
    5353
    54                         if ( ast::Type const * type = mapper( node ) ) {
    55                                 ast::Type const * newType = type->accept( *visitor );
    56                                 assert( newType == nullptr || newType == type );
     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;
    5760                        }
     61                }
    5862
    59                         if ( count != -1 && count < minimum ) minimum = count;
     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 );
    6069                }
    61         }
    6270
    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         }
     71        public:
     72                int result() const { return 0 <= count ? count : 0; }
    7073
    71 public:
    72         int result() const { return 0 <= count ? count : 0; }
     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; }
    7378
    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; }
     79                void postvisit( const ast::StructInstType * ) { if ( count >= 0 ) ++count; }
     80                void postvisit( const ast::UnionInstType * ) { if ( count >= 0 ) ++count; }
    7881
    79         void postvisit( const ast::StructInstType * ) { if ( 0 <= count ) ++count; }
    80         void postvisit( const ast::UnionInstType * ) { if ( 0 <= count ) ++count; }
     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                }
    8192
    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         }
     93                // Look for polymorphic parameters.
     94                void previsit( const ast::StructInstType * sty ) {
     95                        count = minimumPresent( sty->params, expr_result );
     96                }
    9297
    93         // Look for polymorphic parameters.
    94         void previsit( const ast::StructInstType * sty ) {
    95                 count = minimumPresent( sty->params, expr_result );
    96         }
     98                // Look for polymorphic parameters.
     99                void previsit( const ast::UnionInstType * uty ) {
     100                        count = minimumPresent( uty->params, expr_result );
     101                }
    97102
    98         // Look for polymorphic parameters.
    99         void previsit( const ast::UnionInstType * uty ) {
    100                 count = minimumPresent( uty->params, expr_result );
    101         }
     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; }
    102106
    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

    rf7f997a r16e0dcb  
    1616#pragma once
    1717
     18class Type;
    1819namespace ast {
    1920    class Type;
     
    2223namespace ResolvExpr {
    2324
     25int specCost( Type * type );
    2426int specCost( const ast::Type * type );
    2527
  • src/ResolvExpr/Unify.cc

    rf7f997a r16e0dcb  
    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                         }
     541                        // return otherInst;
    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 );
    630634        };
    631635
  • src/ResolvExpr/Unify.h

    rf7f997a r16e0dcb  
    1515
    1616#pragma once
     17
     18#include <list>                   // for list
    1719
    1820#include "AST/Node.hpp"             // for ptr
     
    4547        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    4648        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    47         const ast::OpenVarSet & open, WidenMode widen,
     49        const ast::OpenVarSet & open, WidenMode widen, 
    4850        ast::ptr<ast::Type> & common );
    4951
    5052bool typesCompatible(
    51         const ast::Type *, const ast::Type *,
     53        const ast::Type *, const ast::Type *, 
    5254        const ast::TypeEnvironment & env = {} );
    5355
  • src/ResolvExpr/WidenMode.h

    rf7f997a r16e0dcb  
    1717
    1818namespace ResolvExpr {
     19        struct WidenMode {
     20                WidenMode( bool first, bool second ): first( first ), second( second ) {}
    1921
    20 struct WidenMode {
    21         WidenMode( bool first, bool second ): first( first ), second( second ) {}
     22                WidenMode &operator|=( const WidenMode &other ) {
     23                        first |= other.first; second |= other.second; return *this;
     24                }
    2225
    23         WidenMode &operator|=( const WidenMode &other ) {
    24                 first |= other.first; second |= other.second; return *this;
    25         }
     26                WidenMode &operator&=( const WidenMode &other ) {
     27                        first &= other.first; second &= other.second; return *this;
     28                }
    2629
    27         WidenMode &operator&=( const WidenMode &other ) {
    28                 first &= other.first; second &= other.second; return *this;
    29         }
     30                WidenMode operator|( const WidenMode &other ) {
     31                        WidenMode newWM( *this ); newWM |= other; return newWM;
     32                }
    3033
    31         WidenMode operator|( const WidenMode &other ) {
    32                 WidenMode newWM( *this ); newWM |= other; return newWM;
    33         }
     34                WidenMode operator&( const WidenMode &other ) {
     35                        WidenMode newWM( *this ); newWM &= other; return newWM;
     36                }
    3437
    35         WidenMode operator&( const WidenMode &other ) {
    36                 WidenMode newWM( *this ); newWM &= other; return newWM;
    37         }
     38                operator bool() { return first && second; }
    3839
    39         operator bool() { return first && second; }
     40                bool first : 1, second : 1;
     41        };
    4042
    41         bool first : 1, second : 1;
    42 };
    43 
    44 static inline WidenMode noWiden() { return { false, false }; }
    45 
     43        static inline WidenMode noWiden() { return { false, false }; }
    4644} // namespace ResolvExpr
    4745
  • tests/exceptions/.expect/cardgame.x86.txt

    rf7f997a r16e0dcb  
    11start
     220
     337
     423
     57
    261
     7115
     8115
    390
    4 1
     1062
     118
     1241
     134294967295
     140
     1592
     16134
     178
     1867
     1923
     2027
     21138
     22133
     234
     2459
     2579
     26122
     2723
     285
    5292
    6 1
    7 3
    8 1
    9 1
     3033
     3115
     32106
    10330
    11 2
    12 1
    13 5
    14 0
     3414
     3590
     364294967295
     3781
     3839
     394294967295
     4036
     41116
     42160
     4376
     44127
    15454
    16 0
    17 2
    18 1
    19 0
     4629
     476
     4812
     499
     5018
    20513
    2152done
Note: See TracChangeset for help on using the changeset viewer.