Changes in / [dab09ad:fb0ae06]


Ignore:
Files:
6 added
68 edited

Legend:

Unmodified
Added
Removed
  • configure.ac

    rdab09ad rfb0ae06  
    2424#Trasforming cc1 will break compilation
    2525M4CFA_PROGRAM_NAME
     26
     27#==============================================================================
     28# New AST toggling support
     29AH_TEMPLATE([CFA_USE_NEW_AST],[Sets whether or not to use the new-ast, this is adefault value and can be overrided by --old-ast and --new-ast])
     30AC_ARG_ENABLE(new-ast,
     31        [  --enable-new-ast     whether or not to use new ast as the default AST algorithm],
     32        [case "${enableval}" in
     33                yes) newast=true ;;
     34                no)  newast=false ;;
     35                *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;;
     36        esac],[newast=false])
     37AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast)
    2638
    2739#==============================================================================
  • libcfa/src/Makefile.am

    rdab09ad rfb0ae06  
    4444
    4545headers = common.hfa fstream.hfa heap.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa \
    46                 time.hfa stdlib.hfa memory.hfa parseargs.hfa \
     46                time.hfa stdlib.hfa parseargs.hfa \
    4747                containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
    4848
  • libcfa/src/concurrency/ready_queue.cfa

    rdab09ad rfb0ae06  
    419419        // Actually pop the list
    420420        struct $thread * thrd;
    421         bool emptied;
    422         [thrd, emptied] = pop(lane);
     421        thrd = pop(lane);
    423422
    424423        /* paranoid */ verify(thrd);
     
    457456                        if(head(lane)->link.next == thrd) {
    458457                                $thread * pthrd;
    459                                 bool emptied;
    460                                 [pthrd, emptied] = pop(lane);
     458                                pthrd = pop(lane);
    461459
    462460                                /* paranoid */ verify( pthrd == thrd );
     
    608606                        while(!is_empty(lanes.data[idx])) {
    609607                                struct $thread * thrd;
    610                                 __attribute__((unused)) bool _;
    611                                 [thrd, _] = pop(lanes.data[idx]);
     608                                thrd = pop(lanes.data[idx]);
    612609
    613610                                push(cltr, thrd);
  • libcfa/src/concurrency/ready_subqueue.hfa

    rdab09ad rfb0ae06  
    144144// returns popped
    145145// returns true of lane was empty before push, false otherwise
    146 [$thread *, bool] pop(__intrusive_lane_t & this) {
     146$thread * pop(__intrusive_lane_t & this) {
    147147        /* paranoid */ verify(this.lock);
    148148        /* paranoid */ verify(this.before.link.ts != 0ul);
     
    162162        head->link.next = next;
    163163        next->link.prev = head;
    164         node->link.[next, prev] = 0p;
     164        node->link.next = 0p;
     165        node->link.prev = 0p;
    165166
    166167        // Update head time stamp
     
    180181                /* paranoid */ verify(tail(this)->link.prev == head(this));
    181182                /* paranoid */ verify(head(this)->link.next == tail(this));
    182                 return [node, true];
     183                return node;
    183184        }
    184185        else {
     
    187188                /* paranoid */ verify(head(this)->link.next != tail(this));
    188189                /* paranoid */ verify(this.before.link.ts != 0);
    189                 return [node, false];
     190                return node;
    190191        }
    191192}
  • src/AST/Attribute.hpp

    rdab09ad rfb0ae06  
    5151        template<typename node_t>
    5252        friend node_t * mutate(const node_t * node);
     53        template<typename node_t>
     54    friend node_t * shallowCopy(const node_t * node);
    5355};
    5456
  • src/AST/CVQualifiers.hpp

    rdab09ad rfb0ae06  
    2727                Restrict = 1 << 1,
    2828                Volatile = 1 << 2,
    29                 Lvalue   = 1 << 3,
    30                 Mutex    = 1 << 4,
    31                 Atomic   = 1 << 5,
    32                 NumQualifiers = 6
     29                Mutex    = 1 << 3,
     30                Atomic   = 1 << 4,
     31                NumQualifiers = 5
    3332        };
    3433
    3534        /// Mask for equivalence-preserving qualfiers
    36         enum { EquivQualifiers = ~(Restrict | Lvalue) };
     35        enum { EquivQualifiers = ~Restrict };
    3736
    3837        /// Underlying data for qualifiers
     
    4443                                bool is_restrict : 1;
    4544                                bool is_volatile : 1;
    46                                 bool is_lvalue   : 1;
    4745                                bool is_mutex    : 1;
    4846                                bool is_atomic   : 1;
  • src/AST/Convert.cpp

    rdab09ad rfb0ae06  
    2020
    2121#include "AST/Attribute.hpp"
     22#include "AST/Copy.hpp"
    2223#include "AST/Decl.hpp"
    2324#include "AST/Expr.hpp"
     
    587588                assert( tgtResnSlots.empty() );
    588589
    589                 if ( srcInferred.mode == ast::Expr::InferUnion::Params ) {
     590                if ( srcInferred.data.inferParams ) {
    590591                        const ast::InferredParams &srcParams = srcInferred.inferParams();
    591592                        for (auto & srcParam : srcParams) {
     
    593594                                        srcParam.second.decl,
    594595                                        get<Declaration>().accept1(srcParam.second.declptr),
    595                                         get<Type>().accept1(srcParam.second.actualType),
    596                                         get<Type>().accept1(srcParam.second.formalType),
    597                                         get<Expression>().accept1(srcParam.second.expr)
     596                                        get<Type>().accept1(srcParam.second.actualType)->clone(),
     597                                        get<Type>().accept1(srcParam.second.formalType)->clone(),
     598                                        get<Expression>().accept1(srcParam.second.expr)->clone()
    598599                                ));
    599600                                assert(res.second);
    600601                        }
    601                 } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots  ) {
     602                }
     603                if ( srcInferred.data.resnSlots ) {
    602604                        const ast::ResnSlots &srcSlots = srcInferred.resnSlots();
    603605                        for (auto srcSlot : srcSlots) {
     
    620622
    621623                tgt->result = get<Type>().accept1(src->result);
     624                // Unconditionally use a clone of the result type.
     625                // We know this will leak some objects: much of the immediate conversion result.
     626                // In some cases, using the conversion result directly gives unintended object sharing.
     627                // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache.
     628                // But tgt->result must be fully owned privately by tgt.
     629                // Applying these conservative copies here means
     630                // - weak references point at the declaration's copy, not these expr.result copies (good)
     631                // - we copy more objects than really needed (bad, tolerated)
     632                if (tgt->result) {
     633                        tgt->result = tgt->result->clone();
     634                }
    622635                return visitBaseExpr_skipResultType(src, tgt);
    623636        }
     
    979992
    980993        const ast::Expr * visit( const ast::StmtExpr * node ) override final {
     994                auto stmts = node->stmts;
     995                // disable sharing between multiple StmtExprs explicitly.
     996                if (inCache(stmts)) {
     997                        stmts = ast::deepCopy(stmts.get());
     998                }
    981999                auto rslt = new StmtExpr(
    982                         get<CompoundStmt>().accept1(node->stmts)
     1000                        get<CompoundStmt>().accept1(stmts)
    9831001                );
    9841002
     
    19862004
    19872005                assert( oldInferParams.empty() || oldResnSlots.empty() );
    1988                 assert( newInferred.mode == ast::Expr::InferUnion::Empty );
     2006                // assert( newInferred.mode == ast::Expr::InferUnion::Empty );
    19892007
    19902008                if ( !oldInferParams.empty() ) {
     
    21172135                                old->location,
    21182136                                GET_ACCEPT_1(member, DeclWithType),
    2119                                 GET_ACCEPT_1(aggregate, Expr)
     2137                                GET_ACCEPT_1(aggregate, Expr),
     2138                                ast::MemberExpr::NoOpConstructionChosen
    21202139                        )
    21212140                );
  • src/AST/Decl.cpp

    rdab09ad rfb0ae06  
    5050
    5151const Type * FunctionDecl::get_type() const { return type.get(); }
    52 void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); }
     52void FunctionDecl::set_type( const Type * t ) {
     53        type = strict_dynamic_cast< const FunctionType * >( t );
     54}
    5355
    5456// --- TypeDecl
  • src/AST/Decl.hpp

    rdab09ad rfb0ae06  
    3333
    3434// Must be included in *all* AST classes; should be #undef'd at the end of the file
    35 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     35#define MUTATE_FRIEND \
     36    template<typename node_t> friend node_t * mutate(const node_t * node); \
     37        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3638
    3739namespace ast {
     
    8890        virtual const Type * get_type() const = 0;
    8991        /// Set type of this declaration. May be verified by subclass
    90         virtual void set_type(Type *) = 0;
     92        virtual void set_type( const Type * ) = 0;
    9193
    9294        const DeclWithType * accept( Visitor & v ) const override = 0;
     
    111113
    112114        const Type* get_type() const override { return type; }
    113         void set_type( Type * ty ) override { type = ty; }
     115        void set_type( const Type * ty ) override { type = ty; }
    114116
    115117        const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
     
    133135
    134136        const Type * get_type() const override;
    135         void set_type(Type * t) override;
     137        void set_type( const Type * t ) override;
    136138
    137139        bool has_body() const { return stmts; }
     
    150152        std::vector<ptr<DeclWithType>> assertions;
    151153
    152         NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
    153                 Type* b, Linkage::Spec spec = Linkage::Cforall )
     154        NamedTypeDecl(
     155                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
     156                const Type * b, Linkage::Spec spec = Linkage::Cforall )
    154157        : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
    155158
     
    186189        };
    187190
    188         TypeDecl( const CodeLocation & loc, const std::string & name, Storage::Classes storage, Type * b,
    189                           Kind k, bool s, Type * i = nullptr )
    190                 : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ),
    191                 init( i ) {}
     191        TypeDecl(
     192                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
     193                const Type * b, TypeDecl::Kind k, bool s, const Type * i = nullptr )
     194        : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeDecl::Ttype || s ),
     195          init( i ) {}
    192196
    193197        const char * typeString() const override;
  • src/AST/Expr.cpp

    rdab09ad rfb0ae06  
    2020#include <vector>
    2121
     22#include "Copy.hpp"                // for shallowCopy
     23#include "Eval.hpp"                // for call
    2224#include "GenericSubstitution.hpp"
     25#include "LinkageSpec.hpp"
    2326#include "Stmt.hpp"
    2427#include "Type.hpp"
     
    2730#include "Common/SemanticError.h"
    2831#include "GenPoly/Lvalue.h"        // for referencesPermissable
    29 #include "InitTweak/InitTweak.h"   // for getPointerBase
     32#include "InitTweak/InitTweak.h"   // for getFunction, getPointerBase
    3033#include "ResolvExpr/typeops.h"    // for extractResultType
    3134#include "Tuples/Tuples.h"         // for makeTupleType
    3235
    3336namespace ast {
     37
     38namespace {
     39        std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
     40}
     41
     42// --- Expr
     43bool Expr::get_lvalue() const {
     44        return false;
     45}
    3446
    3547// --- ApplicationExpr
     
    4658}
    4759
     60bool ApplicationExpr::get_lvalue() const {
     61        if ( const DeclWithType * func = InitTweak::getFunction( this ) ) {
     62                return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
     63        }
     64        return false;
     65}
     66
    4867// --- UntypedExpr
    4968
     
    5170        assert( arg );
    5271
    53         UntypedExpr * ret = new UntypedExpr{
    54                 loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
    55         };
     72        UntypedExpr * ret = call( loc, "*?", arg );
    5673        if ( const Type * ty = arg->result ) {
    5774                const Type * base = InitTweak::getPointerBase( ty );
     
    6582                        // base type
    6683                        ret->result = base;
    67                         add_qualifiers( ret->result, CV::Lvalue );
    6884                }
    6985        }
    7086        return ret;
     87}
     88
     89bool UntypedExpr::get_lvalue() const {
     90        std::string fname = InitTweak::getFunctionName( this );
     91        return lvalueFunctionNames.count( fname );
    7192}
    7293
     
    7495        assert( lhs && rhs );
    7596
    76         UntypedExpr * ret = new UntypedExpr{
    77                 loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
    78         };
     97        UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
    7998        if ( lhs->result && rhs->result ) {
    8099                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
     
    108127AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) {
    109128        if ( arg->result ) {
    110                 if ( arg->result->is_lvalue() ) {
     129                if ( arg->get_lvalue() ) {
    111130                        // lvalue, retains all levels of reference, and gains a pointer inside the references
    112131                        Type * res = addrType( arg->result );
    113                         res->set_lvalue( false ); // result of & is never an lvalue
    114132                        result = res;
    115133                } else {
     
    118136                                        dynamic_cast< const ReferenceType * >( arg->result.get() ) ) {
    119137                                Type * res = addrType( refType->base );
    120                                 res->set_lvalue( false ); // result of & is never an lvalue
    121138                                result = res;
    122139                        } else {
     
    139156: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
    140157
     158bool CastExpr::get_lvalue() const {
     159        // This is actually wrong by C, but it works with our current set-up.
     160        return arg->get_lvalue();
     161}
     162
    141163// --- KeywordCastExpr
    142164
    143165const char * KeywordCastExpr::targetString() const {
    144166        return AggregateDecl::aggrString( target );
     167}
     168
     169// --- UntypedMemberExpr
     170
     171bool UntypedMemberExpr::get_lvalue() const {
     172        return aggregate->get_lvalue();
    145173}
    146174
     
    153181        assert( aggregate->result );
    154182
    155         // take ownership of member type
    156         result = mem->get_type();
     183        // Deep copy on result type avoids mutation on transitively multiply referenced object.
     184        //
     185        // Example, adapted from parts of builtins and bootloader:
     186        //
     187        // forall(dtype T)
     188        // struct __Destructor {
     189        //   T * object;
     190        //   void (*dtor)(T *);
     191        // };
     192        //
     193        // forall(dtype S)
     194        // void foo(__Destructor(S) &d) {
     195        //   if (d.dtor) {  // here
     196        //   }
     197        // }
     198        //
     199        // Let e be the "d.dtor" guard espression, which is MemberExpr after resolve.  Let d be the
     200        // declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level
     201        // declaration of __Destructor.  Consider the types e.result and d.type.  In the old AST, one
     202        // is a clone of the other.  Ordinary new-AST use would set them up as a multiply-referenced
     203        // object.
     204        //
     205        // e.result: PointerType
     206        // .base: FunctionType
     207        // .params.front(): ObjectDecl, the anonymous parameter of type T*
     208        // .type: PointerType
     209        // .base: TypeInstType
     210        // let x = that
     211        // let y = similar, except start from d.type
     212        //
     213        // Consider two code lines down, genericSubstitution(...).apply(result).
     214        //
     215        // Applying this chosen-candidate's type substitution means modifying x, substituting
     216        // S for T.  This mutation should affect x and not y.
     217
     218        result = deepCopy(mem->get_type());
     219
    157220        // substitute aggregate generic parameters into member type
    158221        genericSubstitution( aggregate->result ).apply( result );
    159         // ensure lvalue and appropriate restrictions from aggregate type
    160         add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue );
     222        // ensure appropriate restrictions from aggregate type
     223        add_qualifiers( result, aggregate->result->qualifiers );
     224}
     225
     226MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
     227    MemberExpr::NoOpConstruction overloadSelector )
     228: Expr( loc ), member( mem ), aggregate( agg ) {
     229        assert( member );
     230        assert( aggregate );
     231        assert( aggregate->result );
     232        (void) overloadSelector;
     233}
     234
     235bool MemberExpr::get_lvalue() const {
     236        // This is actually wrong by C, but it works with our current set-up.
     237        return true;
    161238}
    162239
     
    170247        assert( var );
    171248        assert( var->get_type() );
    172         result = var->get_type();
    173         add_qualifiers( result, CV::Lvalue );
     249        result = shallowCopy( var->get_type() );
     250}
     251
     252bool VariableExpr::get_lvalue() const {
     253        // It isn't always an lvalue, but it is never an rvalue.
     254        return true;
    174255}
    175256
     
    258339: Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
    259340
     341// --- CommaExpr
     342bool CommaExpr::get_lvalue() const {
     343        // This is wrong by C, but the current implementation uses it.
     344        // (ex: Specialize, Lvalue and Box)
     345        return arg2->get_lvalue();
     346}
     347
    260348// --- ConstructorExpr
    261349
     
    276364        assert( t && i );
    277365        result = t;
    278         add_qualifiers( result, CV::Lvalue );
     366}
     367
     368bool CompoundLiteralExpr::get_lvalue() const {
     369        return true;
    279370}
    280371
     
    293384        // like MemberExpr, TupleIndexExpr is always an lvalue
    294385        result = type->types[ index ];
    295         add_qualifiers( result, CV::Lvalue );
     386}
     387
     388bool TupleIndexExpr::get_lvalue() const {
     389        return tuple->get_lvalue();
    296390}
    297391
  • src/AST/Expr.hpp

    rdab09ad rfb0ae06  
    3131
    3232// Must be included in *all* AST classes; should be #undef'd at the end of the file
    33 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     33#define MUTATE_FRIEND \
     34    template<typename node_t> friend node_t * mutate(const node_t * node); \
     35        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     36
    3437
    3538class ConverterOldToNew;
     
    4245struct ParamEntry {
    4346        UniqueId decl;
    44         ptr<Decl> declptr;
     47        readonly<Decl> declptr;
    4548        ptr<Type> actualType;
    4649        ptr<Type> formalType;
     
    6265class Expr : public ParseNode {
    6366public:
    64         /// Saves space (~16 bytes) by combining ResnSlots and InferredParams
     67        /*
     68         * NOTE: the union approach is incorrect until the case of
     69         * partial resolution in InferMatcher is eliminated.
     70         * it is reverted to allow unresolved and resolved parameters
     71         * to coexist in an expression node.
     72         */
    6573        struct InferUnion {
     74                // mode is now unused
    6675                enum { Empty, Slots, Params } mode;
    67                 union data_t {
    68                         char def;
    69                         ResnSlots resnSlots;
    70                         InferredParams inferParams;
    71 
    72                         data_t() : def('\0') {}
    73                         ~data_t() {}
     76                struct data_t {
     77                        // char def;
     78                        ResnSlots * resnSlots;
     79                        InferredParams * inferParams;
     80
     81                        data_t(): resnSlots(nullptr), inferParams(nullptr) {}
     82                        data_t(const data_t &other) = delete;
     83                        ~data_t() {
     84                                delete resnSlots;
     85                                delete inferParams;
     86                        }
    7487                } data;
    7588
    7689                /// initializes from other InferUnion
    7790                void init_from( const InferUnion& o ) {
    78                         switch ( o.mode ) {
    79                         case Empty:  return;
    80                         case Slots:  new(&data.resnSlots) ResnSlots{ o.data.resnSlots }; return;
    81                         case Params: new(&data.inferParams) InferredParams{ o.data.inferParams }; return;
     91                        if (o.data.resnSlots) {
     92                                data.resnSlots = new ResnSlots(*o.data.resnSlots);
     93                        }
     94                        if (o.data.inferParams) {
     95                                data.inferParams = new InferredParams(*o.data.inferParams);
    8296                        }
    8397                }
     
    8599                /// initializes from other InferUnion (move semantics)
    86100                void init_from( InferUnion&& o ) {
    87                         switch ( o.mode ) {
    88                         case Empty:  return;
    89                         case Slots:  new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return;
    90                         case Params:
    91                                 new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return;
    92                         }
    93                 }
    94 
    95                 /// clears variant fields
    96                 void reset() {
    97                         switch( mode ) {
    98                         case Empty:  return;
    99                         case Slots:  data.resnSlots.~ResnSlots(); return;
    100                         case Params: data.inferParams.~InferredParams(); return;
    101                         }
     101                        data.resnSlots = o.data.resnSlots;
     102                        data.inferParams = o.data.inferParams;
     103                        o.data.resnSlots = nullptr;
     104                        o.data.inferParams = nullptr;
    102105                }
    103106
     
    107110                InferUnion& operator= ( const InferUnion& ) = delete;
    108111                InferUnion& operator= ( InferUnion&& ) = delete;
    109                 ~InferUnion() { reset(); }
     112
     113                bool hasSlots() const { return data.resnSlots; }
    110114
    111115                ResnSlots& resnSlots() {
    112                         switch (mode) {
    113                         case Empty: new(&data.resnSlots) ResnSlots{}; mode = Slots; // fallthrough
    114                         case Slots: return data.resnSlots;
    115                         case Params: assertf(false, "Cannot return to resnSlots from Params"); abort();
     116                        if (!data.resnSlots) {
     117                                data.resnSlots = new ResnSlots();
    116118                        }
    117                         assertf(false, "unreachable");
     119                        return *data.resnSlots;
    118120                }
    119121
    120122                const ResnSlots& resnSlots() const {
    121                         if (mode == Slots) {
    122                                 return data.resnSlots;
     123                        if (data.resnSlots) {
     124                                return *data.resnSlots;
    123125                        }
    124126                        assertf(false, "Mode was not already resnSlots");
     
    127129
    128130                InferredParams& inferParams() {
    129                         switch (mode) {
    130                         case Slots: data.resnSlots.~ResnSlots(); // fallthrough
    131                         case Empty: new(&data.inferParams) InferredParams{}; mode = Params; // fallthrough
    132                         case Params: return data.inferParams;
     131                        if (!data.inferParams) {
     132                                data.inferParams = new InferredParams();
    133133                        }
    134                         assertf(false, "unreachable");
     134                        return *data.inferParams;
    135135                }
    136136
    137137                const InferredParams& inferParams() const {
    138                         if (mode == Params) {
    139                                 return data.inferParams;
     138                        if (data.inferParams) {
     139                                return *data.inferParams;
    140140                        }
    141141                        assertf(false, "Mode was not already Params");
     
    143143                }
    144144
    145                 void set_inferParams( InferredParams && ps ) {
    146                         switch(mode) {
    147                         case Slots:
    148                                 data.resnSlots.~ResnSlots();
    149                                 // fallthrough
    150                         case Empty:
    151                                 new(&data.inferParams) InferredParams{ std::move( ps ) };
    152                                 mode = Params;
    153                                 break;
    154                         case Params:
    155                                 data.inferParams = std::move( ps );
    156                                 break;
    157                         }
     145                void set_inferParams( InferredParams * ps ) {
     146                        delete data.resnSlots;
     147                        data.resnSlots = nullptr;
     148                        delete data.inferParams;
     149                        data.inferParams = ps;
    158150                }
    159151
     
    161153                /// and the other is in `Params`.
    162154                void splice( InferUnion && o ) {
    163                         if ( o.mode == Empty ) return;
    164                         if ( mode == Empty ) { init_from( o ); return; }
    165                         assert( mode == o.mode && "attempt to splice incompatible InferUnion" );
    166 
    167                         if ( mode == Slots ){
    168                                 data.resnSlots.insert(
    169                                         data.resnSlots.end(), o.data.resnSlots.begin(), o.data.resnSlots.end() );
    170                         } else if ( mode == Params ) {
    171                                 for ( const auto & p : o.data.inferParams ) {
    172                                         data.inferParams[p.first] = std::move(p.second);
     155                        if (o.data.resnSlots) {
     156                                if (data.resnSlots) {
     157                                        data.resnSlots->insert(
     158                                                data.resnSlots->end(), o.data.resnSlots->begin(), o.data.resnSlots->end() );
     159                                        delete o.data.resnSlots;
    173160                                }
    174                         } else assertf(false, "invalid mode");
     161                                else {
     162                                        data.resnSlots = o.data.resnSlots;
     163                                }
     164                                o.data.resnSlots = nullptr;
     165                        }
     166
     167                        if (o.data.inferParams) {
     168                                if (data.inferParams) {
     169                                        for ( const auto & p : *o.data.inferParams ) {
     170                                                (*data.inferParams)[p.first] = std::move(p.second);
     171                                        }
     172                                        delete o.data.inferParams;
     173                                }
     174                                else {
     175                                        data.inferParams = o.data.inferParams;
     176                                }
     177                                o.data.inferParams = nullptr;
     178                        }
    175179                }
    176180        };
     
    185189
    186190        Expr * set_extension( bool ex ) { extension = ex; return this; }
     191        virtual bool get_lvalue() const;
    187192
    188193        virtual const Expr * accept( Visitor & v ) const override = 0;
     
    201206        ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} );
    202207
     208        bool get_lvalue() const final;
     209
    203210        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    204211private:
     
    215222        UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} )
    216223        : Expr( loc ), func( f ), args( std::move(as) ) {}
     224
     225        bool get_lvalue() const final;
    217226
    218227        /// Creates a new dereference expression
     
    291300        CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {}
    292301
     302        bool get_lvalue() const final;
     303
    293304        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    294305private:
     
    338349        : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); }
    339350
     351        bool get_lvalue() const final;
     352
    340353        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    341354private:
     
    352365        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg );
    353366
     367        bool get_lvalue() const final;
     368
    354369        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    355370private:
    356371        MemberExpr * clone() const override { return new MemberExpr{ *this }; }
    357372        MUTATE_FRIEND
     373
     374        // Custructor overload meant only for AST conversion
     375        enum NoOpConstruction { NoOpConstructionChosen };
     376        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
     377            NoOpConstruction overloadSelector );
     378        friend class ::ConverterOldToNew;
     379        friend class ::ConverterNewToOld;
    358380};
    359381
     
    365387        VariableExpr( const CodeLocation & loc );
    366388        VariableExpr( const CodeLocation & loc, const DeclWithType * v );
     389
     390        bool get_lvalue() const final;
    367391
    368392        /// generates a function pointer for a given function
     
    532556
    533557        CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 )
    534         : Expr( loc ), arg1( a1 ), arg2( a2 ) {}
     558        : Expr( loc ), arg1( a1 ), arg2( a2 ) {
     559                this->result = a2->result;
     560        }
     561
     562        bool get_lvalue() const final;
    535563
    536564        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    605633        CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i );
    606634
     635        bool get_lvalue() const final;
     636
    607637        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    608638private:
     
    660690
    661691        TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i );
     692
     693        bool get_lvalue() const final;
    662694
    663695        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

    rdab09ad rfb0ae06  
    1010// Created On       : Wed May  8 16:05:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun 24 09:48:00 2019
    13 // Update Count     : 1
     12// Last Modified On : Thr Jul 23 14:15:00 2020
     13// Update Count     : 2
    1414//
    1515
     
    108108class FunctionType;
    109109class ReferenceToType;
    110 class StructInstType;
    111 class UnionInstType;
    112 class EnumInstType;
     110template<typename decl_t> class SueInstType;
     111using StructInstType = SueInstType<StructDecl>;
     112using UnionInstType = SueInstType<UnionDecl>;
     113using EnumInstType = SueInstType<EnumDecl>;
    113114class TraitInstType;
    114115class TypeInstType;
  • src/AST/GenericSubstitution.cpp

    rdab09ad rfb0ae06  
    6262        Pass<GenericSubstitutionBuilder> builder;
    6363        maybe_accept( ty, builder );
    64         return std::move(builder.pass.sub);
     64        return std::move(builder.core.sub);
    6565}
    6666
  • src/AST/Init.hpp

    rdab09ad rfb0ae06  
    2525
    2626// Must be included in *all* AST classes; should be #undef'd at the end of the file
    27 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     27#define MUTATE_FRIEND \
     28    template<typename node_t> friend node_t * mutate(const node_t * node); \
     29        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    2830
    2931namespace ast {
  • src/AST/Node.cpp

    rdab09ad rfb0ae06  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 16 14:16:00 2019
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Jun  5 10:21:00 2020
     13// Update Count     : 1
    1414//
    1515
     
    1717#include "Fwd.hpp"
    1818
     19#include <csignal>  // MEMORY DEBUG -- for raise
    1920#include <iostream>
    2021
     
    2930#include "Print.hpp"
    3031
    31 template< typename node_t, enum ast::Node::ref_type ref_t >
    32 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
    33 
    34 template< typename node_t, enum ast::Node::ref_type ref_t >
    35 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
    36 
    37 template< typename node_t, enum ast::Node::ref_type ref_t >
    38 void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
     32/// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object.
     33/// Process to use in GDB:
     34///   break ast::Node::_trap()
     35///   run
     36///   set variable MEM_TRAP_OBJ = <target>
     37///   disable <first breakpoint>
     38///   continue
     39void * MEM_TRAP_OBJ = nullptr;
     40
     41void _trap( const void * node ) {
     42        if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP);
     43}
     44
     45[[noreturn]] static inline void strict_fail(const ast::Node * node) {
     46        assertf(node, "strict_as had nullptr input.");
     47        const ast::ParseNode * parse = dynamic_cast<const ast::ParseNode *>( node );
     48        if ( nullptr == parse ) {
     49                assertf(nullptr, "%s (no location)", toString(node).c_str());
     50        } else if ( parse->location.isUnset() ) {
     51                assertf(nullptr, "%s (unset location)", toString(node).c_str());
     52        } else {
     53                assertf(nullptr, "%s (at %s:%d)", toString(node).c_str(),
     54                        parse->location.filename.c_str(), parse->location.first_line);
     55        }
     56}
     57
     58template< typename node_t, enum ast::Node::ref_type ref_t >
     59void ast::ptr_base<node_t, ref_t>::_strict_fail() const {
     60        strict_fail(node);
     61}
     62
     63template< typename node_t, enum ast::Node::ref_type ref_t >
     64void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
     65        node->increment(ref_t);
     66        _trap( node );
     67}
     68
     69template< typename node_t, enum ast::Node::ref_type ref_t >
     70void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) {
     71        _trap( node );
     72        node->decrement( ref_t, do_delete );
     73}
     74
     75template< typename node_t, enum ast::Node::ref_type ref_t >
     76void ast::ptr_base<node_t, ref_t>::_check() const {
     77        // if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
     78}
    3979
    4080template< typename node_t, enum ast::Node::ref_type ref_t >
  • src/AST/Node.hpp

    rdab09ad rfb0ae06  
    1010// Created On       : Wed May 8 10:27:04 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun  3 13:26:00 2019
    13 // Update Count     : 5
     12// Last Modified On : Fri Jun 5 9:47:00 2020
     13// Update Count     : 6
    1414//
    1515
     
    3838        Node& operator= (const Node&) = delete;
    3939        Node& operator= (Node&&) = delete;
    40         virtual ~Node() = default;
     40        virtual ~Node() {}
    4141
    4242        virtual const Node * accept( Visitor & v ) const = 0;
     
    5757        template<typename node_t>
    5858        friend node_t * mutate(const node_t * node);
     59        template<typename node_t>
     60        friend node_t * shallowCopy(const node_t * node);
    5961
    6062        mutable size_t strong_count = 0;
     
    6971        }
    7072
    71         void decrement(ast::Node::ref_type ref) const {
     73        void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
    7274                switch (ref) {
    7375                        case ref_type::strong: strong_count--; break;
     
    7577                }
    7678
    77                 if(!strong_count && !weak_count) {
     79                if( do_delete && !strong_count && !weak_count) {
    7880                        delete this;
    7981                }
     
    9496        assertf(
    9597                node->weak_count == 0,
    96                 "Error: mutating node with weak references to it will invalided some references"
     98                "Error: mutating node with weak references to it will invalidate some references"
    9799        );
    98100        return node->clone();
     
    104106        // skip mutate if equivalent
    105107        if ( node->*field == val ) return node;
    106        
     108
    107109        // mutate and return
    108110        node_t * ret = mutate( node );
     
    123125        (ret->*field)[i] = std::forward< field_t >( val );
    124126        return ret;
     127}
     128
     129/// Mutate an entire indexed collection by cloning to accepted value
     130template<typename node_t, typename parent_t, typename coll_t>
     131const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) {
     132        for ( unsigned i = 0; i < (node->*field).size(); ++i ) {
     133                node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) );
     134        }
     135        return node;
    125136}
    126137
     
    219230        operator const node_t * () const { _check(); return node; }
    220231
     232        const node_t * release() {
     233                const node_t * ret = node;
     234                if ( node ) {
     235                        _dec(node, false);
     236                        node = nullptr;
     237                }
     238                return ret;
     239        }
     240
    221241        /// wrapper for convenient access to dynamic_cast
    222242        template<typename o_node_t>
    223243        const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); }
    224244
    225         /// wrapper for convenient access to strict_dynamic_cast
     245        /// Wrapper that makes sure dynamic_cast returns non-null.
    226246        template<typename o_node_t>
    227         const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); }
     247        const o_node_t * strict_as() const {
     248                if (const o_node_t * ret = as<o_node_t>()) return ret;
     249                _strict_fail();
     250        }
     251
     252        /// Wrapper that makes sure dynamic_cast does not fail.
     253        template<typename o_node_t, decltype(nullptr) null>
     254        const o_node_t * strict_as() const { return node ? strict_as<o_node_t>() : nullptr; }
    228255
    229256        /// Returns a mutable version of the pointer in this node.
     
    244271
    245272        void _inc( const node_t * other );
    246         void _dec( const node_t * other );
     273        void _dec( const node_t * other, bool do_delete = true );
    247274        void _check() const;
     275        void _strict_fail() const __attribute__((noreturn));
    248276
    249277        const node_t * node;
  • src/AST/Pass.hpp

    rdab09ad rfb0ae06  
    88//
    99// Author           : Thierry Delisle
    10 // Created On       : Thu May 09 15::37::05 2019
     10// Created On       : Thu May 09 15:37:05 2019
    1111// Last Modified By :
    1212// Last Modified On :
     
    3535#include "AST/SymbolTable.hpp"
    3636
     37#include "AST/ForallSubstitutionTable.hpp"
     38
    3739// Private prelude header, needed for some of the magic tricks this class pulls off
    3840#include "AST/Pass.proto.hpp"
     
    4648//
    4749// Several additional features are available through inheritance
    48 // | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
    49 //                          current expression
    50 // | WithStmtsToAdd       - provides the ability to insert statements before or after the current
    51 //                          statement by adding new statements into stmtsToAddBefore or
    52 //                          stmtsToAddAfter respectively.
    53 // | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
    54 //                          declarations by adding new DeclStmt into declsToAddBefore or
    55 //                          declsToAddAfter respectively.
    56 // | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
    57 //                          to false in pre{visit,visit} to skip visiting children
    58 // | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
    59 //                          call GuardValue with the variable to save, the variable will
    60 //                          automatically be restored to its previous value after the corresponding
    61 //                          postvisit/postmutate teminates.
    62 // | WithVisitorRef       - provides an pointer to the templated visitor wrapper
    63 // | WithSymbolTable      - provides symbol table functionality
     50// | WithTypeSubstitution  - provides polymorphic const TypeSubstitution * env for the
     51//                           current expression
     52// | WithStmtsToAdd        - provides the ability to insert statements before or after the current
     53//                           statement by adding new statements into stmtsToAddBefore or
     54//                           stmtsToAddAfter respectively.
     55// | WithDeclsToAdd        - provides the ability to insert declarations before or after the
     56//                           current declarations by adding new DeclStmt into declsToAddBefore or
     57//                           declsToAddAfter respectively.
     58// | WithShortCircuiting   - provides the ability to skip visiting child nodes; set visit_children
     59//                           to false in pre{visit,visit} to skip visiting children
     60// | WithGuards            - provides the ability to save/restore data like a LIFO stack; to save,
     61//                           call GuardValue with the variable to save, the variable will
     62//                           automatically be restored to its previous value after the
     63//                           corresponding postvisit/postmutate teminates.
     64// | WithVisitorRef        - provides an pointer to the templated visitor wrapper
     65// | WithSymbolTable       - provides symbol table functionality
     66// | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
    6467//-------------------------------------------------------------------------------------------------
    65 template< typename pass_t >
     68template< typename core_t >
    6669class Pass final : public ast::Visitor {
    6770public:
     71        using core_type = core_t;
     72        using type = Pass<core_t>;
     73
    6874        /// Forward any arguments to the pass constructor
    6975        /// Propagate 'this' if necessary
    7076        template< typename... Args >
    7177        Pass( Args &&... args)
    72                 : pass( std::forward<Args>( args )... )
     78                : core( std::forward<Args>( args )... )
    7379        {
    7480                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    75                 typedef Pass<pass_t> this_t;
    76                 this_t * const * visitor = __pass::visitor(pass, 0);
     81                type * const * visitor = __pass::visitor(core, 0);
    7782                if(visitor) {
    78                         *const_cast<this_t **>( visitor ) = this;
     83                        *const_cast<type **>( visitor ) = this;
    7984                }
    8085        }
     
    8287        virtual ~Pass() = default;
    8388
     89        /// Construct and run a pass on a translation unit.
     90        template< typename... Args >
     91        static void run( std::list< ptr<Decl> > & decls, Args &&... args ) {
     92                Pass<core_t> visitor( std::forward<Args>( args )... );
     93                accept_all( decls, visitor );
     94        }
     95
    8496        /// Storage for the actual pass
    85         pass_t pass;
     97        core_t core;
    8698
    8799        /// Visit function declarations
     
    179191        const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
    180192
    181         template<typename pass_type>
    182         friend void accept_all( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor );
     193        template<typename core_type>
     194        friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
    183195private:
    184196
    185         bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
     197        bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; }
    186198
    187199private:
     
    202214        container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    203215
     216        /// Mutate forall-list, accounting for presence of type substitution map
     217        template<typename node_t>
     218        void mutate_forall( const node_t *& );
     219
    204220public:
    205221        /// Logic to call the accept and mutate the parent if needed, delegates call to accept
     
    210226        /// Internal RAII guard for symbol table features
    211227        struct guard_symtab {
    212                 guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }
    213                 ~guard_symtab()                                   { __pass::symtab::leave(pass, 0); }
    214                 Pass<pass_t> & pass;
     228                guard_symtab( Pass<core_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.core, 0); }
     229                ~guard_symtab()                                   { __pass::symtab::leave(pass.core, 0); }
     230                Pass<core_t> & pass;
    215231        };
    216232
    217233        /// Internal RAII guard for scope features
    218234        struct guard_scope {
    219                 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
    220                 ~guard_scope()                                   { __pass::scope::leave(pass, 0); }
    221                 Pass<pass_t> & pass;
     235                guard_scope( Pass<core_t> & pass ): pass( pass ) { __pass::scope::enter(pass.core, 0); }
     236                ~guard_scope()                                   { __pass::scope::leave(pass.core, 0); }
     237                Pass<core_t> & pass;
     238        };
     239
     240        /// Internal RAII guard for forall substitutions
     241        struct guard_forall_subs {
     242                guard_forall_subs( Pass<core_t> & pass, const ParameterizedType * type )
     243                : pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
     244                ~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
     245                Pass<core_t> & pass;
     246                const ParameterizedType * type;
    222247        };
    223248
     
    227252
    228253/// Apply a pass to an entire translation unit
    229 template<typename pass_t>
    230 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
     254template<typename core_t>
     255void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
    231256
    232257//-------------------------------------------------------------------------------------------------
     
    268293        };
    269294
    270         template< typename pass_t>
    271         friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );
     295        template< typename core_t>
     296        friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup );
    272297public:
    273298
     
    305330
    306331/// Used to get a pointer to the pass with its wrapped type
    307 template<typename pass_t>
     332template<typename core_t>
    308333struct WithVisitorRef {
    309         Pass<pass_t> * const visitor = nullptr;
     334        Pass<core_t> * const visitor = nullptr;
    310335};
    311336
     
    314339        SymbolTable symtab;
    315340};
     341
     342/// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
     343struct WithForallSubstitutor {
     344        ForallSubstitutionTable subs;
     345};
     346
    316347}
    317348
     
    321352extern struct PassVisitorStats {
    322353        size_t depth = 0;
    323         Stats::Counters::MaxCounter<double> * max = nullptr;
    324         Stats::Counters::AverageCounter<double> * avg = nullptr;
     354        Stats::Counters::MaxCounter<double> * max;
     355        Stats::Counters::AverageCounter<double> * avg;
    325356} pass_visitor_stats;
    326357}
  • src/AST/Pass.impl.hpp

    rdab09ad rfb0ae06  
    2525        using namespace ast; \
    2626        /* back-up the visit children */ \
    27         __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
     27        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \
    2828        /* setup the scope for passes that want to run code at exit */ \
    29         __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
     29        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (core, 0) ); \
     30        /* begin tracing memory allocation if requested by this pass */ \
     31        __pass::beginTrace( core, 0 ); \
    3032        /* call the implementation of the previsit of this pass */ \
    31         __pass::previsit( pass, node, 0 );
     33        __pass::previsit( core, node, 0 );
    3234
    3335#define VISIT( code... ) \
     
    4042#define VISIT_END( type, node ) \
    4143        /* call the implementation of the postvisit of this pass */ \
    42         auto __return = __pass::postvisit( pass, node, 0 ); \
     44        auto __return = __pass::postvisit( core, node, 0 ); \
    4345        assertf(__return, "post visit should never return null"); \
     46        /* end tracing memory allocation if requested by this pass */ \
     47        __pass::endTrace( core, 0 ); \
    4448        return __return;
    4549
     
    119123        }
    120124
    121         template< typename pass_t >
     125        template< typename core_t >
    122126        template< typename node_t >
    123         auto ast::Pass< pass_t >::call_accept( const node_t * node )
     127        auto ast::Pass< core_t >::call_accept( const node_t * node )
    124128                -> typename std::enable_if<
    125129                                !std::is_base_of<ast::Expr, node_t>::value &&
     
    127131                        , decltype( node->accept(*this) )
    128132                >::type
    129 
    130133        {
    131134                __pedantic_pass_assert( __visit_children() );
    132                 __pedantic_pass_assert( expr );
     135                __pedantic_pass_assert( node );
    133136
    134137                static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
     
    138141        }
    139142
    140         template< typename pass_t >
    141         const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {
     143        template< typename core_t >
     144        const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
    142145                __pedantic_pass_assert( __visit_children() );
    143146                __pedantic_pass_assert( expr );
    144147
    145                 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
     148                const ast::TypeSubstitution ** env_ptr = __pass::env( core, 0);
    146149                if ( env_ptr && expr->env ) {
    147150                        *env_ptr = expr->env;
     
    151154        }
    152155
    153         template< typename pass_t >
    154         const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
     156        template< typename core_t >
     157        const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
    155158                __pedantic_pass_assert( __visit_children() );
    156159                __pedantic_pass_assert( stmt );
     
    160163
    161164                // get the stmts/decls that will need to be spliced in
    162                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    163                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    164                 auto decls_before = __pass::declsToAddBefore( pass, 0);
    165                 auto decls_after  = __pass::declsToAddAfter ( pass, 0);
     165                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     166                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
     167                auto decls_before = __pass::declsToAddBefore( core, 0);
     168                auto decls_after  = __pass::declsToAddAfter ( core, 0);
    166169
    167170                // These may be modified by subnode but most be restored once we exit this statemnet.
    168                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0) );
     171                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( core, 0) );
    169172                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    170173                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    202205        }
    203206
    204         template< typename pass_t >
     207        template< typename core_t >
    205208        template< template <class...> class container_t >
    206         container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     209        container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    207210                __pedantic_pass_assert( __visit_children() );
    208211                if( statements.empty() ) return {};
     
    215218
    216219                // get the stmts/decls that will need to be spliced in
    217                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    218                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    219                 auto decls_before = __pass::declsToAddBefore( pass, 0);
    220                 auto decls_after  = __pass::declsToAddAfter ( pass, 0);
     220                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     221                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
     222                auto decls_before = __pass::declsToAddBefore( core, 0);
     223                auto decls_after  = __pass::declsToAddAfter ( core, 0);
    221224
    222225                // These may be modified by subnode but most be restored once we exit this statemnet.
     
    268271        }
    269272
    270         template< typename pass_t >
     273        template< typename core_t >
    271274        template< template <class...> class container_t, typename node_t >
    272         container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     275        container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    273276                __pedantic_pass_assert( __visit_children() );
    274277                if( container.empty() ) return {};
     
    299302        }
    300303
    301         template< typename pass_t >
     304        template< typename core_t >
    302305        template<typename node_t, typename parent_t, typename child_t>
    303         void ast::Pass< pass_t >::maybe_accept(
     306        void ast::Pass< core_t >::maybe_accept(
    304307                const node_t * & parent,
    305308                child_t parent_t::*child
     
    323326        }
    324327
     328
     329        template< typename core_t >
     330        template< typename node_t >
     331        void ast::Pass< core_t >::mutate_forall( const node_t *& node ) {
     332                if ( auto subs = __pass::forall::subs( core, 0 ) ) {
     333                        // tracking TypeDecl substitution, full clone
     334                        if ( node->forall.empty() ) return;
     335
     336                        node_t * mut = mutate( node );
     337                        mut->forall = subs->clone( node->forall, *this );
     338                        node = mut;
     339                } else {
     340                        // not tracking TypeDecl substitution, just mutate
     341                        maybe_accept( node, &node_t::forall );
     342                }
     343        }
    325344}
    326345
     
    333352//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    334353
    335 template< typename pass_t >
    336 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
     354template< typename core_t >
     355inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) {
    337356        // We are going to aggregate errors for all these statements
    338357        SemanticErrorException errors;
     
    342361
    343362        // get the stmts/decls that will need to be spliced in
    344         auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
    345         auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
     363        auto decls_before = __pass::declsToAddBefore( visitor.core, 0);
     364        auto decls_after  = __pass::declsToAddAfter ( visitor.core, 0);
    346365
    347366        // update pass statitistics
     
    392411//--------------------------------------------------------------------------
    393412// ObjectDecl
    394 template< typename pass_t >
    395 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
     413template< typename core_t >
     414const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) {
    396415        VISIT_START( node );
    397416
     
    406425        )
    407426
    408         __pass::symtab::addId( pass, 0, node );
     427        __pass::symtab::addId( core, 0, node );
    409428
    410429        VISIT_END( DeclWithType, node );
     
    413432//--------------------------------------------------------------------------
    414433// FunctionDecl
    415 template< typename pass_t >
    416 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
    417         VISIT_START( node );
    418 
    419         __pass::symtab::addId( pass, 0, node );
     434template< typename core_t >
     435const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) {
     436        VISIT_START( node );
     437
     438        __pass::symtab::addId( core, 0, node );
    420439
    421440        VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
     
    425444                // shadow with exprs and not the other way around.
    426445                guard_symtab guard { *this };
    427                 __pass::symtab::addWith( pass, 0, node->withExprs, node );
     446                __pass::symtab::addWith( core, 0, node->withExprs, node );
    428447                {
    429448                        guard_symtab guard { *this };
    430449                        // implicit add __func__ identifier as specified in the C manual 6.4.2.2
    431                         static ast::ObjectDecl func(
    432                                 node->location, "__func__",
    433                                 new ast::ArrayType(
    434                                         new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
     450                        static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{
     451                                CodeLocation{}, "__func__",
     452                                new ast::ArrayType{
     453                                        new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
    435454                                        nullptr, VariableLen, DynamicDim
    436                                 )
    437                         );
    438                         __pass::symtab::addId( pass, 0, &func );
     455                                }
     456                        } };
     457                        __pass::symtab::addId( core, 0, func );
    439458                        VISIT(
    440459                                maybe_accept( node, &FunctionDecl::type );
     
    454473//--------------------------------------------------------------------------
    455474// StructDecl
    456 template< typename pass_t >
    457 const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
     475template< typename core_t >
     476const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) {
    458477        VISIT_START( node );
    459478
    460479        // make up a forward declaration and add it before processing the members
    461480        // needs to be on the heap because addStruct saves the pointer
    462         __pass::symtab::addStructFwd( pass, 0, node );
     481        __pass::symtab::addStructFwd( core, 0, node );
    463482
    464483        VISIT({
     
    469488
    470489        // this addition replaces the forward declaration
    471         __pass::symtab::addStruct( pass, 0, node );
     490        __pass::symtab::addStruct( core, 0, node );
    472491
    473492        VISIT_END( Decl, node );
     
    476495//--------------------------------------------------------------------------
    477496// UnionDecl
    478 template< typename pass_t >
    479 const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
     497template< typename core_t >
     498const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) {
    480499        VISIT_START( node );
    481500
    482501        // make up a forward declaration and add it before processing the members
    483         __pass::symtab::addUnionFwd( pass, 0, node );
     502        __pass::symtab::addUnionFwd( core, 0, node );
    484503
    485504        VISIT({
     
    489508        })
    490509
    491         __pass::symtab::addUnion( pass, 0, node );
     510        __pass::symtab::addUnion( core, 0, node );
    492511
    493512        VISIT_END( Decl, node );
     
    496515//--------------------------------------------------------------------------
    497516// EnumDecl
    498 template< typename pass_t >
    499 const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
    500         VISIT_START( node );
    501 
    502         __pass::symtab::addEnum( pass, 0, node );
     517template< typename core_t >
     518const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) {
     519        VISIT_START( node );
     520
     521        __pass::symtab::addEnum( core, 0, node );
    503522
    504523        VISIT(
     
    513532//--------------------------------------------------------------------------
    514533// TraitDecl
    515 template< typename pass_t >
    516 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
     534template< typename core_t >
     535const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) {
    517536        VISIT_START( node );
    518537
     
    523542        })
    524543
    525         __pass::symtab::addTrait( pass, 0, node );
     544        __pass::symtab::addTrait( core, 0, node );
    526545
    527546        VISIT_END( Decl, node );
     
    530549//--------------------------------------------------------------------------
    531550// TypeDecl
    532 template< typename pass_t >
    533 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
     551template< typename core_t >
     552const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) {
    534553        VISIT_START( node );
    535554
     
    543562        // note that assertions come after the type is added to the symtab, since they are not part of the type proper
    544563        // and may depend on the type itself
    545         __pass::symtab::addType( pass, 0, node );
     564        __pass::symtab::addType( core, 0, node );
    546565
    547566        VISIT(
     
    559578//--------------------------------------------------------------------------
    560579// TypedefDecl
    561 template< typename pass_t >
    562 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
     580template< typename core_t >
     581const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) {
    563582        VISIT_START( node );
    564583
     
    569588        })
    570589
    571         __pass::symtab::addType( pass, 0, node );
     590        __pass::symtab::addType( core, 0, node );
    572591
    573592        VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
     
    578597//--------------------------------------------------------------------------
    579598// AsmDecl
    580 template< typename pass_t >
    581 const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
     599template< typename core_t >
     600const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) {
    582601        VISIT_START( node );
    583602
     
    591610//--------------------------------------------------------------------------
    592611// StaticAssertDecl
    593 template< typename pass_t >
    594 const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
     612template< typename core_t >
     613const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) {
    595614        VISIT_START( node );
    596615
     
    605624//--------------------------------------------------------------------------
    606625// CompoundStmt
    607 template< typename pass_t >
    608 const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
     626template< typename core_t >
     627const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
    609628        VISIT_START( node );
    610629        VISIT({
    611630                // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    612                 auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
    613                         if ( ! inFunction ) __pass::symtab::enter(pass, 0);
    614                 }, [this, inFunction = this->inFunction]() {
    615                         if ( ! inFunction ) __pass::symtab::leave(pass, 0);
     631                auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {
     632                        if ( ! inFunctionCpy ) __pass::symtab::enter(core, 0);
     633                }, [this, inFunctionCpy = this->inFunction]() {
     634                        if ( ! inFunctionCpy ) __pass::symtab::leave(core, 0);
    616635                });
    617636                ValueGuard< bool > guard2( inFunction );
     
    625644//--------------------------------------------------------------------------
    626645// ExprStmt
    627 template< typename pass_t >
    628 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {
     646template< typename core_t >
     647const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) {
    629648        VISIT_START( node );
    630649
     
    638657//--------------------------------------------------------------------------
    639658// AsmStmt
    640 template< typename pass_t >
    641 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {
     659template< typename core_t >
     660const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) {
    642661        VISIT_START( node )
    643662
     
    654673//--------------------------------------------------------------------------
    655674// DirectiveStmt
    656 template< typename pass_t >
    657 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {
     675template< typename core_t >
     676const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) {
    658677        VISIT_START( node )
    659678
     
    663682//--------------------------------------------------------------------------
    664683// IfStmt
    665 template< typename pass_t >
    666 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
     684template< typename core_t >
     685const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) {
    667686        VISIT_START( node );
    668687
     
    681700//--------------------------------------------------------------------------
    682701// WhileStmt
    683 template< typename pass_t >
    684 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {
     702template< typename core_t >
     703const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) {
    685704        VISIT_START( node );
    686705
     
    698717//--------------------------------------------------------------------------
    699718// ForStmt
    700 template< typename pass_t >
    701 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {
     719template< typename core_t >
     720const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) {
    702721        VISIT_START( node );
    703722
     
    716735//--------------------------------------------------------------------------
    717736// SwitchStmt
    718 template< typename pass_t >
    719 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {
     737template< typename core_t >
     738const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) {
    720739        VISIT_START( node );
    721740
     
    730749//--------------------------------------------------------------------------
    731750// CaseStmt
    732 template< typename pass_t >
    733 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {
     751template< typename core_t >
     752const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) {
    734753        VISIT_START( node );
    735754
     
    744763//--------------------------------------------------------------------------
    745764// BranchStmt
    746 template< typename pass_t >
    747 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {
     765template< typename core_t >
     766const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) {
    748767        VISIT_START( node );
    749768        VISIT_END( Stmt, node );
     
    752771//--------------------------------------------------------------------------
    753772// ReturnStmt
    754 template< typename pass_t >
    755 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {
     773template< typename core_t >
     774const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) {
    756775        VISIT_START( node );
    757776
     
    765784//--------------------------------------------------------------------------
    766785// ThrowStmt
    767 template< typename pass_t >
    768 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {
     786template< typename core_t >
     787const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) {
    769788        VISIT_START( node );
    770789
     
    779798//--------------------------------------------------------------------------
    780799// TryStmt
    781 template< typename pass_t >
    782 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {
     800template< typename core_t >
     801const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) {
    783802        VISIT_START( node );
    784803
     
    794813//--------------------------------------------------------------------------
    795814// CatchStmt
    796 template< typename pass_t >
    797 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
     815template< typename core_t >
     816const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) {
    798817        VISIT_START( node );
    799818
     
    811830//--------------------------------------------------------------------------
    812831// FinallyStmt
    813 template< typename pass_t >
    814 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
     832template< typename core_t >
     833const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) {
    815834        VISIT_START( node );
    816835
     
    824843//--------------------------------------------------------------------------
    825844// FinallyStmt
    826 template< typename pass_t >
    827 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {
     845template< typename core_t >
     846const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) {
    828847        VISIT_START( node );
    829848
     
    837856//--------------------------------------------------------------------------
    838857// WaitForStmt
    839 template< typename pass_t >
    840 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
     858template< typename core_t >
     859const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) {
    841860        VISIT_START( node );
    842861                // for( auto & clause : node->clauses ) {
     
    906925//--------------------------------------------------------------------------
    907926// WithStmt
    908 template< typename pass_t >
    909 const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
     927template< typename core_t >
     928const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) {
    910929        VISIT_START( node );
    911930
     
    915934                        // catch statements introduce a level of scope (for the caught exception)
    916935                        guard_symtab guard { *this };
    917                         __pass::symtab::addWith( pass, 0, node->exprs, node );
     936                        __pass::symtab::addWith( core, 0, node->exprs, node );
    918937                        maybe_accept( node, &WithStmt::stmt );
    919938                }
     
    924943//--------------------------------------------------------------------------
    925944// NullStmt
    926 template< typename pass_t >
    927 const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
     945template< typename core_t >
     946const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) {
    928947        VISIT_START( node );
    929948        VISIT_END( NullStmt, node );
     
    932951//--------------------------------------------------------------------------
    933952// DeclStmt
    934 template< typename pass_t >
    935 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
     953template< typename core_t >
     954const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) {
    936955        VISIT_START( node );
    937956
     
    945964//--------------------------------------------------------------------------
    946965// ImplicitCtorDtorStmt
    947 template< typename pass_t >
    948 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
     966template< typename core_t >
     967const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
    949968        VISIT_START( node );
    950969
    951970        // For now this isn't visited, it is unclear if this causes problem
    952971        // if all tests are known to pass, remove this code
    953         // VISIT(
    954         //      maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
    955         // )
     972        VISIT(
     973                maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
     974        )
    956975
    957976        VISIT_END( Stmt, node );
     
    960979//--------------------------------------------------------------------------
    961980// ApplicationExpr
    962 template< typename pass_t >
    963 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {
     981template< typename core_t >
     982const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) {
    964983        VISIT_START( node );
    965984
     
    978997//--------------------------------------------------------------------------
    979998// UntypedExpr
    980 template< typename pass_t >
    981 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {
     999template< typename core_t >
     1000const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) {
    9821001        VISIT_START( node );
    9831002
     
    9961015//--------------------------------------------------------------------------
    9971016// NameExpr
    998 template< typename pass_t >
    999 const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {
     1017template< typename core_t >
     1018const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) {
    10001019        VISIT_START( node );
    10011020
     
    10101029//--------------------------------------------------------------------------
    10111030// CastExpr
    1012 template< typename pass_t >
    1013 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {
     1031template< typename core_t >
     1032const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) {
    10141033        VISIT_START( node );
    10151034
     
    10261045//--------------------------------------------------------------------------
    10271046// KeywordCastExpr
    1028 template< typename pass_t >
    1029 const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {
     1047template< typename core_t >
     1048const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) {
    10301049        VISIT_START( node );
    10311050
     
    10421061//--------------------------------------------------------------------------
    10431062// VirtualCastExpr
    1044 template< typename pass_t >
    1045 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {
     1063template< typename core_t >
     1064const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) {
    10461065        VISIT_START( node );
    10471066
     
    10581077//--------------------------------------------------------------------------
    10591078// AddressExpr
    1060 template< typename pass_t >
    1061 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {
     1079template< typename core_t >
     1080const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) {
    10621081        VISIT_START( node );
    10631082
     
    10741093//--------------------------------------------------------------------------
    10751094// LabelAddressExpr
    1076 template< typename pass_t >
    1077 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {
     1095template< typename core_t >
     1096const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) {
    10781097        VISIT_START( node );
    10791098
     
    10881107//--------------------------------------------------------------------------
    10891108// UntypedMemberExpr
    1090 template< typename pass_t >
    1091 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {
     1109template< typename core_t >
     1110const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) {
    10921111        VISIT_START( node );
    10931112
     
    11051124//--------------------------------------------------------------------------
    11061125// MemberExpr
    1107 template< typename pass_t >
    1108 const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {
     1126template< typename core_t >
     1127const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) {
    11091128        VISIT_START( node );
    11101129
     
    11211140//--------------------------------------------------------------------------
    11221141// VariableExpr
    1123 template< typename pass_t >
    1124 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {
     1142template< typename core_t >
     1143const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) {
    11251144        VISIT_START( node );
    11261145
     
    11351154//--------------------------------------------------------------------------
    11361155// ConstantExpr
    1137 template< typename pass_t >
    1138 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {
     1156template< typename core_t >
     1157const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) {
    11391158        VISIT_START( node );
    11401159
     
    11491168//--------------------------------------------------------------------------
    11501169// SizeofExpr
    1151 template< typename pass_t >
    1152 const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {
     1170template< typename core_t >
     1171const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) {
    11531172        VISIT_START( node );
    11541173
     
    11691188//--------------------------------------------------------------------------
    11701189// AlignofExpr
    1171 template< typename pass_t >
    1172 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {
     1190template< typename core_t >
     1191const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) {
    11731192        VISIT_START( node );
    11741193
     
    11891208//--------------------------------------------------------------------------
    11901209// UntypedOffsetofExpr
    1191 template< typename pass_t >
    1192 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {
     1210template< typename core_t >
     1211const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) {
    11931212        VISIT_START( node );
    11941213
     
    12051224//--------------------------------------------------------------------------
    12061225// OffsetofExpr
    1207 template< typename pass_t >
    1208 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {
     1226template< typename core_t >
     1227const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) {
    12091228        VISIT_START( node );
    12101229
     
    12211240//--------------------------------------------------------------------------
    12221241// OffsetPackExpr
    1223 template< typename pass_t >
    1224 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {
     1242template< typename core_t >
     1243const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) {
    12251244        VISIT_START( node );
    12261245
     
    12371256//--------------------------------------------------------------------------
    12381257// LogicalExpr
    1239 template< typename pass_t >
    1240 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {
     1258template< typename core_t >
     1259const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) {
    12411260        VISIT_START( node );
    12421261
     
    12541273//--------------------------------------------------------------------------
    12551274// ConditionalExpr
    1256 template< typename pass_t >
    1257 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {
     1275template< typename core_t >
     1276const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) {
    12581277        VISIT_START( node );
    12591278
     
    12721291//--------------------------------------------------------------------------
    12731292// CommaExpr
    1274 template< typename pass_t >
    1275 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {
     1293template< typename core_t >
     1294const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) {
    12761295        VISIT_START( node );
    12771296
     
    12891308//--------------------------------------------------------------------------
    12901309// TypeExpr
    1291 template< typename pass_t >
    1292 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {
     1310template< typename core_t >
     1311const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) {
    12931312        VISIT_START( node );
    12941313
     
    13051324//--------------------------------------------------------------------------
    13061325// AsmExpr
    1307 template< typename pass_t >
    1308 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {
     1326template< typename core_t >
     1327const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) {
    13091328        VISIT_START( node );
    13101329
     
    13221341//--------------------------------------------------------------------------
    13231342// ImplicitCopyCtorExpr
    1324 template< typename pass_t >
    1325 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
     1343template< typename core_t >
     1344const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
    13261345        VISIT_START( node );
    13271346
     
    13381357//--------------------------------------------------------------------------
    13391358// ConstructorExpr
    1340 template< typename pass_t >
    1341 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {
     1359template< typename core_t >
     1360const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) {
    13421361        VISIT_START( node );
    13431362
     
    13541373//--------------------------------------------------------------------------
    13551374// CompoundLiteralExpr
    1356 template< typename pass_t >
    1357 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {
     1375template< typename core_t >
     1376const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) {
    13581377        VISIT_START( node );
    13591378
     
    13701389//--------------------------------------------------------------------------
    13711390// RangeExpr
    1372 template< typename pass_t >
    1373 const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {
     1391template< typename core_t >
     1392const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) {
    13741393        VISIT_START( node );
    13751394
     
    13871406//--------------------------------------------------------------------------
    13881407// UntypedTupleExpr
    1389 template< typename pass_t >
    1390 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {
     1408template< typename core_t >
     1409const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) {
    13911410        VISIT_START( node );
    13921411
     
    14031422//--------------------------------------------------------------------------
    14041423// TupleExpr
    1405 template< typename pass_t >
    1406 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {
     1424template< typename core_t >
     1425const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) {
    14071426        VISIT_START( node );
    14081427
     
    14191438//--------------------------------------------------------------------------
    14201439// TupleIndexExpr
    1421 template< typename pass_t >
    1422 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {
     1440template< typename core_t >
     1441const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) {
    14231442        VISIT_START( node );
    14241443
     
    14351454//--------------------------------------------------------------------------
    14361455// TupleAssignExpr
    1437 template< typename pass_t >
    1438 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {
     1456template< typename core_t >
     1457const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) {
    14391458        VISIT_START( node );
    14401459
     
    14511470//--------------------------------------------------------------------------
    14521471// StmtExpr
    1453 template< typename pass_t >
    1454 const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {
     1472template< typename core_t >
     1473const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) {
    14551474        VISIT_START( node );
    14561475
    14571476        VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
    14581477                // get the stmts that will need to be spliced in
    1459                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    1460                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     1478                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     1479                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
    14611480
    14621481                // These may be modified by subnode but most be restored once we exit this statemnet.
    1463                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );
     1482                ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( core, 0) );
    14641483                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    14651484                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    14791498//--------------------------------------------------------------------------
    14801499// UniqueExpr
    1481 template< typename pass_t >
    1482 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {
     1500template< typename core_t >
     1501const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) {
    14831502        VISIT_START( node );
    14841503
     
    14951514//--------------------------------------------------------------------------
    14961515// UntypedInitExpr
    1497 template< typename pass_t >
    1498 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {
     1516template< typename core_t >
     1517const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) {
    14991518        VISIT_START( node );
    15001519
     
    15121531//--------------------------------------------------------------------------
    15131532// InitExpr
    1514 template< typename pass_t >
    1515 const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {
     1533template< typename core_t >
     1534const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) {
    15161535        VISIT_START( node );
    15171536
     
    15291548//--------------------------------------------------------------------------
    15301549// DeletedExpr
    1531 template< typename pass_t >
    1532 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {
     1550template< typename core_t >
     1551const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) {
    15331552        VISIT_START( node );
    15341553
     
    15461565//--------------------------------------------------------------------------
    15471566// DefaultArgExpr
    1548 template< typename pass_t >
    1549 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {
     1567template< typename core_t >
     1568const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) {
    15501569        VISIT_START( node );
    15511570
     
    15621581//--------------------------------------------------------------------------
    15631582// GenericExpr
    1564 template< typename pass_t >
    1565 const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {
     1583template< typename core_t >
     1584const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) {
    15661585        VISIT_START( node );
    15671586
     
    16021621//--------------------------------------------------------------------------
    16031622// VoidType
    1604 template< typename pass_t >
    1605 const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {
     1623template< typename core_t >
     1624const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) {
    16061625        VISIT_START( node );
    16071626
     
    16111630//--------------------------------------------------------------------------
    16121631// BasicType
    1613 template< typename pass_t >
    1614 const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {
     1632template< typename core_t >
     1633const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) {
    16151634        VISIT_START( node );
    16161635
     
    16201639//--------------------------------------------------------------------------
    16211640// PointerType
    1622 template< typename pass_t >
    1623 const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {
     1641template< typename core_t >
     1642const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) {
    16241643        VISIT_START( node );
    16251644
     
    16341653//--------------------------------------------------------------------------
    16351654// ArrayType
    1636 template< typename pass_t >
    1637 const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {
     1655template< typename core_t >
     1656const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) {
    16381657        VISIT_START( node );
    16391658
     
    16481667//--------------------------------------------------------------------------
    16491668// ReferenceType
    1650 template< typename pass_t >
    1651 const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {
     1669template< typename core_t >
     1670const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) {
    16521671        VISIT_START( node );
    16531672
     
    16611680//--------------------------------------------------------------------------
    16621681// QualifiedType
    1663 template< typename pass_t >
    1664 const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {
     1682template< typename core_t >
     1683const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) {
    16651684        VISIT_START( node );
    16661685
     
    16751694//--------------------------------------------------------------------------
    16761695// FunctionType
    1677 template< typename pass_t >
    1678 const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) {
    1679         VISIT_START( node );
    1680 
    1681         VISIT(
    1682                 maybe_accept( node, &FunctionType::forall  );
     1696template< typename core_t >
     1697const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) {
     1698        VISIT_START( node );
     1699
     1700        VISIT({
     1701                guard_forall_subs forall_guard { *this, node };
     1702                mutate_forall( node );
    16831703                maybe_accept( node, &FunctionType::returns );
    16841704                maybe_accept( node, &FunctionType::params  );
    1685         )
     1705        })
    16861706
    16871707        VISIT_END( Type, node );
     
    16901710//--------------------------------------------------------------------------
    16911711// StructInstType
    1692 template< typename pass_t >
    1693 const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {
    1694         VISIT_START( node );
    1695 
    1696         __pass::symtab::addStruct( pass, 0, node->name );
     1712template< typename core_t >
     1713const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) {
     1714        VISIT_START( node );
     1715
     1716        __pass::symtab::addStruct( core, 0, node->name );
    16971717
    16981718        VISIT({
    16991719                guard_symtab guard { *this };
    1700                 maybe_accept( node, &StructInstType::forall );
     1720                guard_forall_subs forall_guard { *this, node };
     1721                mutate_forall( node );
    17011722                maybe_accept( node, &StructInstType::params );
    17021723        })
     
    17071728//--------------------------------------------------------------------------
    17081729// UnionInstType
    1709 template< typename pass_t >
    1710 const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {
    1711         VISIT_START( node );
    1712 
    1713         __pass::symtab::addStruct( pass, 0, node->name );
    1714 
    1715         {
     1730template< typename core_t >
     1731const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) {
     1732        VISIT_START( node );
     1733
     1734        __pass::symtab::addUnion( core, 0, node->name );
     1735
     1736        VISIT({
    17161737                guard_symtab guard { *this };
    1717                 maybe_accept( node, &UnionInstType::forall );
     1738                guard_forall_subs forall_guard { *this, node };
     1739                mutate_forall( node );
    17181740                maybe_accept( node, &UnionInstType::params );
    1719         }
     1741        })
    17201742
    17211743        VISIT_END( Type, node );
     
    17241746//--------------------------------------------------------------------------
    17251747// EnumInstType
    1726 template< typename pass_t >
    1727 const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) {
    1728         VISIT_START( node );
    1729 
    1730         VISIT(
    1731                 maybe_accept( node, &EnumInstType::forall );
     1748template< typename core_t >
     1749const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) {
     1750        VISIT_START( node );
     1751
     1752        VISIT({
     1753                guard_forall_subs forall_guard { *this, node };
     1754                mutate_forall( node );
    17321755                maybe_accept( node, &EnumInstType::params );
    1733         )
     1756        })
    17341757
    17351758        VISIT_END( Type, node );
     
    17381761//--------------------------------------------------------------------------
    17391762// TraitInstType
    1740 template< typename pass_t >
    1741 const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) {
    1742         VISIT_START( node );
    1743 
    1744         VISIT(
    1745                 maybe_accept( node, &TraitInstType::forall );
     1763template< typename core_t >
     1764const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) {
     1765        VISIT_START( node );
     1766
     1767        VISIT({
     1768                guard_forall_subs forall_guard { *this, node };
     1769                mutate_forall( node );
    17461770                maybe_accept( node, &TraitInstType::params );
    1747         )
     1771        })
    17481772
    17491773        VISIT_END( Type, node );
     
    17521776//--------------------------------------------------------------------------
    17531777// TypeInstType
    1754 template< typename pass_t >
    1755 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) {
    1756         VISIT_START( node );
    1757 
    1758         VISIT(
    1759                 maybe_accept( node, &TypeInstType::forall );
    1760                 maybe_accept( node, &TypeInstType::params );
     1778template< typename core_t >
     1779const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) {
     1780        VISIT_START( node );
     1781
     1782        VISIT(
     1783                {
     1784                        guard_forall_subs forall_guard { *this, node };
     1785                        mutate_forall( node );
     1786                        maybe_accept( node, &TypeInstType::params );
     1787                }
     1788                // ensure that base re-bound if doing substitution
     1789                __pass::forall::replace( core, 0, node );
    17611790        )
    17621791
     
    17661795//--------------------------------------------------------------------------
    17671796// TupleType
    1768 template< typename pass_t >
    1769 const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {
     1797template< typename core_t >
     1798const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) {
    17701799        VISIT_START( node );
    17711800
     
    17801809//--------------------------------------------------------------------------
    17811810// TypeofType
    1782 template< typename pass_t >
    1783 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {
     1811template< typename core_t >
     1812const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) {
    17841813        VISIT_START( node );
    17851814
     
    17931822//--------------------------------------------------------------------------
    17941823// VarArgsType
    1795 template< typename pass_t >
    1796 const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {
     1824template< typename core_t >
     1825const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) {
    17971826        VISIT_START( node );
    17981827
     
    18021831//--------------------------------------------------------------------------
    18031832// ZeroType
    1804 template< typename pass_t >
    1805 const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {
     1833template< typename core_t >
     1834const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) {
    18061835        VISIT_START( node );
    18071836
     
    18111840//--------------------------------------------------------------------------
    18121841// OneType
    1813 template< typename pass_t >
    1814 const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {
     1842template< typename core_t >
     1843const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) {
    18151844        VISIT_START( node );
    18161845
     
    18201849//--------------------------------------------------------------------------
    18211850// GlobalScopeType
    1822 template< typename pass_t >
    1823 const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {
     1851template< typename core_t >
     1852const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) {
    18241853        VISIT_START( node );
    18251854
     
    18301859//--------------------------------------------------------------------------
    18311860// Designation
    1832 template< typename pass_t >
    1833 const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {
     1861template< typename core_t >
     1862const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) {
    18341863        VISIT_START( node );
    18351864
     
    18411870//--------------------------------------------------------------------------
    18421871// SingleInit
    1843 template< typename pass_t >
    1844 const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
     1872template< typename core_t >
     1873const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) {
    18451874        VISIT_START( node );
    18461875
     
    18541883//--------------------------------------------------------------------------
    18551884// ListInit
    1856 template< typename pass_t >
    1857 const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
     1885template< typename core_t >
     1886const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) {
    18581887        VISIT_START( node );
    18591888
     
    18681897//--------------------------------------------------------------------------
    18691898// ConstructorInit
    1870 template< typename pass_t >
    1871 const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
     1899template< typename core_t >
     1900const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) {
    18721901        VISIT_START( node );
    18731902
     
    18831912//--------------------------------------------------------------------------
    18841913// Attribute
    1885 template< typename pass_t >
    1886 const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
     1914template< typename core_t >
     1915const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node  )  {
    18871916        VISIT_START( node );
    18881917
     
    18961925//--------------------------------------------------------------------------
    18971926// TypeSubstitution
    1898 template< typename pass_t >
    1899 const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
     1927template< typename core_t >
     1928const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) {
    19001929        VISIT_START( node );
    19011930
     
    19071936                                guard_symtab guard { *this };
    19081937                                auto new_node = p.second->accept( *this );
    1909                                 if (new_node != p.second) mutated = false;
     1938                                if (new_node != p.second) mutated = true;
    19101939                                new_map.insert({ p.first, new_node });
    19111940                        }
     
    19231952                                guard_symtab guard { *this };
    19241953                                auto new_node = p.second->accept( *this );
    1925                                 if (new_node != p.second) mutated = false;
     1954                                if (new_node != p.second) mutated = true;
    19261955                                new_map.insert({ p.first, new_node });
    19271956                        }
  • src/AST/Pass.proto.hpp

    rdab09ad rfb0ae06  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
     19#include "Common/Stats/Heap.h"
     20
    1921namespace ast {
    20 template<typename pass_type>
     22template<typename core_t>
    2123class Pass;
    2224
     
    8284                };
    8385
    84                 std::stack< cleanup_t > cleanups;
     86                std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
    8587        };
    8688
     
    111113        /// "Short hand" to check if this is a valid previsit function
    112114        /// Mostly used to make the static_assert look (and print) prettier
    113         template<typename pass_t, typename node_t>
     115        template<typename core_t, typename node_t>
    114116        struct is_valid_previsit {
    115                 using ret_t = decltype( ((pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );
     117                using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) );
    116118
    117119                static constexpr bool value = std::is_void< ret_t >::value ||
     
    127129        template<>
    128130        struct __assign<true> {
    129                 template<typename pass_t, typename node_t>
    130                 static inline void result( pass_t & pass, const node_t * & node ) {
    131                         pass.previsit( node );
     131                template<typename core_t, typename node_t>
     132                static inline void result( core_t & core, const node_t * & node ) {
     133                        core.previsit( node );
    132134                }
    133135        };
     
    135137        template<>
    136138        struct __assign<false> {
    137                 template<typename pass_t, typename node_t>
    138                 static inline void result( pass_t & pass, const node_t * & node ) {
    139                         node = pass.previsit( node );
     139                template<typename core_t, typename node_t>
     140                static inline void result( core_t & core, const node_t * & node ) {
     141                        node = core.previsit( node );
    140142                        assertf(node, "Previsit must not return NULL");
    141143                }
     
    150152        template<>
    151153        struct __return<true> {
    152                 template<typename pass_t, typename node_t>
    153                 static inline const node_t * result( pass_t & pass, const node_t * & node ) {
    154                         pass.postvisit( node );
     154                template<typename core_t, typename node_t>
     155                static inline const node_t * result( core_t & core, const node_t * & node ) {
     156                        core.postvisit( node );
    155157                        return node;
    156158                }
     
    159161        template<>
    160162        struct __return<false> {
    161                 template<typename pass_t, typename node_t>
    162                 static inline auto result( pass_t & pass, const node_t * & node ) {
    163                         return pass.postvisit( node );
     163                template<typename core_t, typename node_t>
     164                static inline auto result( core_t & core, const node_t * & node ) {
     165                        return core.postvisit( node );
    164166                }
    165167        };
     
    180182        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    181183        // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    182         template<typename pass_t, typename node_t>
    183         static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
     184        template<typename core_t, typename node_t>
     185        static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
    184186                static_assert(
    185                         is_valid_previsit<pass_t, node_t>::value,
     187                        is_valid_previsit<core_t, node_t>::value,
    186188                        "Previsit may not change the type of the node. It must return its paremeter or void."
    187189                );
     
    189191                __assign<
    190192                        std::is_void<
    191                                 decltype( pass.previsit( node ) )
     193                                decltype( core.previsit( node ) )
    192194                        >::value
    193                 >::result( pass, node );
     195                >::result( core, node );
    194196        }
    195197
    196         template<typename pass_t, typename node_t>
    197         static inline auto previsit( pass_t &, const node_t *, long ) {}
     198        template<typename core_t, typename node_t>
     199        static inline auto previsit( core_t &, const node_t *, long ) {}
    198200
    199201        // PostVisit : never mutates the passed pointer but may return a different node
    200         template<typename pass_t, typename node_t>
    201         static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->
    202                 decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
     202        template<typename core_t, typename node_t>
     203        static inline auto postvisit( core_t & core, const node_t * node, int ) ->
     204                decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    203205        {
    204206                return __return<
    205207                        std::is_void<
    206                                 decltype( pass.postvisit( node ) )
     208                                decltype( core.postvisit( node ) )
    207209                        >::value
    208                 >::result( pass, node );
     210                >::result( core, node );
    209211        }
    210212
    211         template<typename pass_t, typename node_t>
    212         static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
     213        template<typename core_t, typename node_t>
     214        static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
    213215
    214216        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    225227        // The type is not strictly enforced but does match the accessory
    226228        #define FIELD_PTR( name, default_type ) \
    227         template< typename pass_t > \
    228         static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
     229        template< typename core_t > \
     230        static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
    229231        \
    230         template< typename pass_t > \
    231         static inline default_type * name( pass_t &, long ) { return nullptr; }
     232        template< typename core_t > \
     233        static inline default_type * name( core_t &, long ) { return nullptr; }
    232234
    233235        // List of fields and their expected types
     
    239241        FIELD_PTR( visit_children, __pass::bool_ref )
    240242        FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    241         FIELD_PTR( visitor, ast::Pass<pass_t> * const )
     243        FIELD_PTR( visitor, ast::Pass<core_t> * const )
    242244
    243245        // Remove the macro to make sure we don't clash
    244246        #undef FIELD_PTR
     247
     248        template< typename core_t >
     249        static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     250                // Stats::Heap::stacktrace_push(core_t::traceId);
     251        }
     252
     253        template< typename core_t >
     254        static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     255                // Stats::Heap::stacktrace_pop();
     256        }
     257
     258        template< typename core_t >
     259        static void beginTrace(core_t &, long) {}
     260
     261        template< typename core_t >
     262        static void endTrace(core_t &, long) {}
    245263
    246264        // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     
    248266        // detect it using the same strategy
    249267        namespace scope {
    250                 template<typename pass_t>
    251                 static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
    252                         pass.beginScope();
    253                 }
    254 
    255                 template<typename pass_t>
    256                 static inline void enter( pass_t &, long ) {}
    257 
    258                 template<typename pass_t>
    259                 static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
    260                         pass.endScope();
    261                 }
    262 
    263                 template<typename pass_t>
    264                 static inline void leave( pass_t &, long ) {}
    265         };
    266 
    267         // Finally certain pass desire an up to date symbol table automatically
     268                template<typename core_t>
     269                static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
     270                        core.beginScope();
     271                }
     272
     273                template<typename core_t>
     274                static inline void enter( core_t &, long ) {}
     275
     276                template<typename core_t>
     277                static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
     278                        core.endScope();
     279                }
     280
     281                template<typename core_t>
     282                static inline void leave( core_t &, long ) {}
     283        } // namespace scope
     284
     285        // Certain passes desire an up to date symbol table automatically
    268286        // detect the presence of a member name `symtab` and call all the members appropriately
    269287        namespace symtab {
    270288                // Some simple scoping rules
    271                 template<typename pass_t>
    272                 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {
    273                         pass.symtab.enterScope();
    274                 }
    275 
    276                 template<typename pass_t>
    277                 static inline auto enter( pass_t &, long ) {}
    278 
    279                 template<typename pass_t>
    280                 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {
    281                         pass.symtab.leaveScope();
    282                 }
    283 
    284                 template<typename pass_t>
    285                 static inline auto leave( pass_t &, long ) {}
     289                template<typename core_t>
     290                static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
     291                        core.symtab.enterScope();
     292                }
     293
     294                template<typename core_t>
     295                static inline auto enter( core_t &, long ) {}
     296
     297                template<typename core_t>
     298                static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
     299                        core.symtab.leaveScope();
     300                }
     301
     302                template<typename core_t>
     303                static inline auto leave( core_t &, long ) {}
    286304
    287305                // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
    288306                // Create macro to condense these common patterns
    289307                #define SYMTAB_FUNC1( func, type ) \
    290                 template<typename pass_t> \
    291                 static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.symtab.func( arg ), void() ) {\
    292                         pass.symtab.func( arg ); \
     308                template<typename core_t> \
     309                static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
     310                        core.symtab.func( arg ); \
    293311                } \
    294312                \
    295                 template<typename pass_t> \
    296                 static inline void func( pass_t &, long, type ) {}
     313                template<typename core_t> \
     314                static inline void func( core_t &, long, type ) {}
    297315
    298316                #define SYMTAB_FUNC2( func, type1, type2 ) \
    299                 template<typename pass_t> \
    300                 static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.symtab.func( arg1, arg2 ), void () ) {\
    301                         pass.symtab.func( arg1, arg2 ); \
     317                template<typename core_t> \
     318                static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
     319                        core.symtab.func( arg1, arg2 ); \
    302320                } \
    303321                        \
    304                 template<typename pass_t> \
    305                 static inline void func( pass_t &, long, type1, type2 ) {}
     322                template<typename core_t> \
     323                static inline void func( core_t &, long, type1, type2 ) {}
    306324
    307325                SYMTAB_FUNC1( addId     , const DeclWithType *  );
     
    311329                SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
    312330                SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
    313                 SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
     331                SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
    314332
    315333                // A few extra functions have more complicated behaviour, they are hand written
    316                 template<typename pass_t>
    317                 static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {
     334                template<typename core_t>
     335                static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
    318336                        ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    319337                        fwd->params = decl->params;
    320                         pass.symtab.addStruct( fwd );
    321                 }
    322 
    323                 template<typename pass_t>
    324                 static inline void addStructFwd( pass_t &, long, const ast::StructDecl * ) {}
    325 
    326                 template<typename pass_t>
    327                 static inline auto addUnionFwd( pass_t & pass, int, const ast::UnionDecl * decl ) -> decltype( pass.symtab.addUnion( decl ), void() ) {
     338                        core.symtab.addStruct( fwd );
     339                }
     340
     341                template<typename core_t>
     342                static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
     343
     344                template<typename core_t>
     345                static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
    328346                        UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
    329347                        fwd->params = decl->params;
    330                         pass.symtab.addUnion( fwd );
    331                 }
    332 
    333                 template<typename pass_t>
    334                 static inline void addUnionFwd( pass_t &, long, const ast::UnionDecl * ) {}
    335 
    336                 template<typename pass_t>
    337                 static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addStruct( str ), void() ) {
    338                         if ( ! pass.symtab.lookupStruct( str ) ) {
    339                                 pass.symtab.addStruct( str );
     348                        core.symtab.addUnion( fwd );
     349                }
     350
     351                template<typename core_t>
     352                static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
     353
     354                template<typename core_t>
     355                static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
     356                        if ( ! core.symtab.lookupStruct( str ) ) {
     357                                core.symtab.addStruct( str );
    340358                        }
    341359                }
    342360
    343                 template<typename pass_t>
    344                 static inline void addStruct( pass_t &, long, const std::string & ) {}
    345 
    346                 template<typename pass_t>
    347                 static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addUnion( str ), void() ) {
    348                         if ( ! pass.symtab.lookupUnion( str ) ) {
    349                                 pass.symtab.addUnion( str );
     361                template<typename core_t>
     362                static inline void addStruct( core_t &, long, const std::string & ) {}
     363
     364                template<typename core_t>
     365                static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
     366                        if ( ! core.symtab.lookupUnion( str ) ) {
     367                                core.symtab.addUnion( str );
    350368                        }
    351369                }
    352370
    353                 template<typename pass_t>
    354                 static inline void addUnion( pass_t &, long, const std::string & ) {}
     371                template<typename core_t>
     372                static inline void addUnion( core_t &, long, const std::string & ) {}
    355373
    356374                #undef SYMTAB_FUNC1
    357375                #undef SYMTAB_FUNC2
    358         };
    359 };
    360 };
     376        } // namespace symtab
     377
     378        // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
     379        // Detect the presence of a member name `subs` and call all members appropriately
     380        namespace forall {
     381                // Some simple scoping rules
     382                template<typename core_t>
     383                static inline auto enter( core_t & core, int, const ast::ParameterizedType * type )
     384                -> decltype( core.subs, void() ) {
     385                        if ( ! type->forall.empty() ) core.subs.beginScope();
     386                }
     387
     388                template<typename core_t>
     389                static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {}
     390
     391                template<typename core_t>
     392                static inline auto leave( core_t & core, int, const ast::ParameterizedType * type )
     393                -> decltype( core.subs, void() ) {
     394                        if ( ! type->forall.empty() ) { core.subs.endScope(); }
     395                }
     396
     397                template<typename core_t>
     398                static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {}
     399
     400                // Get the substitution table, if present
     401                template<typename core_t>
     402                static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) {
     403                        return &core.subs;
     404                }
     405
     406                template<typename core_t>
     407                static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; }
     408
     409                // Replaces a TypeInstType's base TypeDecl according to the table
     410                template<typename core_t>
     411                static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
     412                -> decltype( core.subs, void() ) {
     413                        inst = ast::mutate_field(
     414                                inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
     415                }
     416
     417                template<typename core_t>
     418                static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
     419
     420        } // namespace forall
     421} // namespace __pass
     422} // namespace ast
  • src/AST/Print.cpp

    rdab09ad rfb0ae06  
    2929
    3030template <typename C, typename... T>
    31 constexpr auto make_array(T&&... values) ->
    32         array<C,sizeof...(T)>
     31constexpr array<C,sizeof...(T)> make_array(T&&... values)
    3332{
    3433        return array<C,sizeof...(T)>{
     
    129128
    130129        void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
    131                 switch ( inferred.mode ) {
    132                 case ast::Expr::InferUnion::Empty: return;
    133                 case ast::Expr::InferUnion::Slots: {
    134                         os << indent << "with " << inferred.data.resnSlots.size()
     130                if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) {
     131                        os << indent << "with " << inferred.data.resnSlots->size()
    135132                           << " pending inference slots" << endl;
    136                         return;
    137                 }
    138                 case ast::Expr::InferUnion::Params: {
     133                }
     134                if (inferred.data.inferParams && !inferred.data.inferParams->empty()) {
    139135                        os << indent << "with inferred parameters " << level << ":" << endl;
    140136                        ++indent;
    141                         for ( const auto & i : inferred.data.inferParams ) {
     137                        for ( const auto & i : *inferred.data.inferParams ) {
    142138                                os << indent;
    143                                 short_print( Decl::fromId( i.second.decl ) );
     139                                short_print( i.second.declptr );
    144140                                os << endl;
    145141                                print( i.second.expr->inferred, level+1 );
    146142                        }
    147143                        --indent;
    148                         return;
    149                 }
    150144                }
    151145        }
     
    233227                }
    234228
    235                 if ( ! short_mode && ! node->assertions.empty() ) {
     229                if ( ! node->assertions.empty() ) {
    236230                        os << endl << indent << "... with assertions" << endl;
    237231                        ++indent;
     
    842836        virtual const ast::Expr * visit( const ast::CastExpr * node ) override final {
    843837                ++indent;
    844                 os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;
     838                os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent;
    845839                safe_print( node->arg );
    846840                os << endl << indent-1 << "... to:";
  • src/AST/Stmt.hpp

    rdab09ad rfb0ae06  
    2727
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    29 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     29#define MUTATE_FRIEND \
     30    template<typename node_t> friend node_t * mutate(const node_t * node); \
     31        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3032
    3133namespace ast {
     
    412414class ImplicitCtorDtorStmt final : public Stmt {
    413415public:
    414         readonly<Stmt> callStmt;
     416        ptr<Stmt> callStmt;
    415417
    416418        ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
  • src/AST/Type.cpp

    rdab09ad rfb0ae06  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon May 13 15:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 15 16:56:28 2019
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jul 23 14:16:00 2020
     13// Update Count     : 5
    1414//
    1515
     
    2121
    2222#include "Decl.hpp"
     23#include "ForallSubstitutor.hpp" // for substituteForall
    2324#include "Init.hpp"
     25#include "Common/utility.h"      // for copy, move
    2426#include "InitTweak/InitTweak.h" // for getPointerBase
    2527#include "Tuples/Tuples.h"       // for isTtype
     
    9092// GENERATED END
    9193
     94// --- ParameterizedType
     95
     96void ParameterizedType::initWithSub(
     97        const ParameterizedType & o, Pass< ForallSubstitutor > & sub
     98) {
     99        forall = sub.core( o.forall );
     100}
     101
    92102// --- FunctionType
     103
     104FunctionType::FunctionType( const FunctionType & o )
     105: ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(),
     106  isVarArgs( o.isVarArgs ) {
     107        Pass< ForallSubstitutor > sub;
     108        initWithSub( o, sub );           // initialize substitution map
     109        returns = sub.core( o.returns ); // apply to return and parameter types
     110        params = sub.core( o.params );
     111}
    93112
    94113namespace {
     
    106125
    107126// --- ReferenceToType
     127
     128void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) {
     129        ParameterizedType::initWithSub( o, sub ); // initialize substitution
     130        params = sub.core( o.params );            // apply to parameters
     131}
     132
     133ReferenceToType::ReferenceToType( const ReferenceToType & o )
     134: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ),
     135  hoistType( o.hoistType ) {
     136        Pass< ForallSubstitutor > sub;
     137        initWithSub( o, sub );
     138}
     139
    108140std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
    109141        assertf( aggr(), "Must have aggregate to perform lookup" );
     
    116148}
    117149
    118 // --- StructInstType
    119 
    120 StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
    121         std::vector<ptr<Attribute>>&& as )
    122 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    123 
    124 bool StructInstType::isComplete() const { return base ? base->body : false; }
    125 
    126 // --- UnionInstType
    127 
    128 UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
    129         std::vector<ptr<Attribute>>&& as )
    130 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    131 
    132 bool UnionInstType::isComplete() const { return base ? base->body : false; }
    133 
    134 // --- EnumInstType
    135 
    136 EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
    137         std::vector<ptr<Attribute>>&& as )
    138 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    139 
    140 bool EnumInstType::isComplete() const { return base ? base->body : false; }
     150// --- SueInstType (StructInstType, UnionInstType, EnumInstType)
     151
     152template<typename decl_t>
     153SueInstType<decl_t>::SueInstType(
     154        const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     155: ReferenceToType( b->name, q, move(as) ), base( b ) {}
     156
     157template<typename decl_t>
     158bool SueInstType<decl_t>::isComplete() const {
     159        return base ? base->body : false;
     160}
     161
     162template class SueInstType<StructDecl>;
     163template class SueInstType<UnionDecl>;
     164template class SueInstType<EnumDecl>;
    141165
    142166// --- TraitInstType
    143167
    144 TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
    145         std::vector<ptr<Attribute>>&& as )
    146 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     168TraitInstType::TraitInstType(
     169        const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     170: ReferenceToType( b->name, q, move(as) ), base( b ) {}
    147171
    148172// --- TypeInstType
     173
     174TypeInstType::TypeInstType( const TypeInstType & o )
     175: ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
     176        Pass< ForallSubstitutor > sub;
     177        initWithSub( o, sub );      // initialize substitution
     178        base = sub.core( o.base );  // apply to base type
     179}
    149180
    150181void TypeInstType::set_base( const TypeDecl * b ) {
     
    158189
    159190TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    160 : Type( q ), types( std::move(ts) ), members() {
     191: Type( q ), types( move(ts) ), members() {
    161192        // This constructor is awkward. `TupleType` needs to contain objects so that members can be
    162193        // named, but members without initializer nodes end up getting constructors, which breaks
  • src/AST/Type.hpp

    rdab09ad rfb0ae06  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:56:46 2019
    13 // Update Count     : 5
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jul 23 14:15:00 2020
     13// Update Count     : 6
    1414//
    1515
     
    2929
    3030// Must be included in *all* AST classes; should be #undef'd at the end of the file
    31 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     31#define MUTATE_FRIEND \
     32    template<typename node_t> friend node_t * mutate(const node_t * node); \
     33        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3234
    3335namespace ast {
     36
     37template< typename T > class Pass;
     38
     39struct ForallSubstitutor;
    3440
    3541class Type : public Node {
     
    4450        bool is_volatile() const { return qualifiers.is_volatile; }
    4551        bool is_restrict() const { return qualifiers.is_restrict; }
    46         bool is_lvalue() const { return qualifiers.is_lvalue; }
    4752        bool is_mutex() const { return qualifiers.is_mutex; }
    4853        bool is_atomic() const { return qualifiers.is_atomic; }
     
    5156        Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; }
    5257        Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
    53         Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }
    5458        Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
    5559        Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
     
    163167        static const char *typeNames[];
    164168
    165         BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
     169        BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    166170        : Type(q, std::move(as)), kind(k) {}
    167171
     
    265269/// Base type for potentially forall-qualified types
    266270class ParameterizedType : public Type {
     271protected:
     272        /// initializes forall with substitutor
     273        void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub );
    267274public:
    268275        using ForallList = std::vector<ptr<TypeDecl>>;
     
    276283        ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
    277284        : Type(q, std::move(as)), forall() {}
     285
     286        // enforce use of ForallSubstitutor to copy parameterized type
     287        ParameterizedType( const ParameterizedType & ) = delete;
     288
     289        ParameterizedType( ParameterizedType && ) = default;
     290
     291        // no need to change destructor, and operator= deleted in Node
    278292
    279293private:
     
    301315        : ParameterizedType(q), returns(), params(), isVarArgs(va) {}
    302316
     317        FunctionType( const FunctionType & o );
     318
    303319        /// true if either the parameters or return values contain a tttype
    304320        bool isTtype() const;
     
    314330/// base class for types that refer to types declared elsewhere (aggregates and typedefs)
    315331class ReferenceToType : public ParameterizedType {
     332protected:
     333        /// Initializes forall and parameters based on substitutor
     334        void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub );
    316335public:
    317336        std::vector<ptr<Expr>> params;
     
    319338        bool hoistType = false;
    320339
    321         ReferenceToType( const std::string& n, CV::Qualifiers q = {},
    322                 std::vector<ptr<Attribute>> && as = {} )
     340        ReferenceToType(
     341                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    323342        : ParameterizedType(q, std::move(as)), params(), name(n) {}
     343
     344        ReferenceToType( const ReferenceToType & o );
    324345
    325346        /// Gets aggregate declaration this type refers to
     
    333354};
    334355
    335 /// instance of struct type
    336 class StructInstType final : public ReferenceToType {
    337 public:
    338         readonly<StructDecl> base;
    339 
    340         StructInstType( const std::string& n, CV::Qualifiers q = {},
    341                 std::vector<ptr<Attribute>> && as = {} )
     356// Common implementation for the SUE instance types. Not to be used directly.
     357template<typename decl_t>
     358class SueInstType final : public ReferenceToType {
     359public:
     360        using base_type = decl_t;
     361        readonly<decl_t> base;
     362
     363        SueInstType(
     364                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    342365        : ReferenceToType( n, q, std::move(as) ), base() {}
    343         StructInstType( const StructDecl * b, CV::Qualifiers q = {},
    344                 std::vector<ptr<Attribute>> && as = {} );
     366
     367        SueInstType(
     368                const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    345369
    346370        bool isComplete() const override;
    347371
    348         const StructDecl * aggr() const override { return base; }
    349 
    350         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    351 private:
    352         StructInstType * clone() const override { return new StructInstType{ *this }; }
    353         MUTATE_FRIEND
    354 };
    355 
    356 /// instance of union type
    357 class UnionInstType final : public ReferenceToType {
    358 public:
    359         readonly<UnionDecl> base;
    360 
    361         UnionInstType( const std::string& n, CV::Qualifiers q = {},
    362                 std::vector<ptr<Attribute>> && as = {} )
     372        const decl_t * aggr() const override { return base; }
     373
     374        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     375private:
     376        SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; }
     377        MUTATE_FRIEND
     378};
     379
     380/// An instance of a struct type.
     381using StructInstType = SueInstType<StructDecl>;
     382
     383/// An instance of a union type.
     384using UnionInstType = SueInstType<UnionDecl>;
     385
     386/// An instance of an enum type.
     387using EnumInstType = SueInstType<EnumDecl>;
     388
     389/// An instance of a trait type.
     390class TraitInstType final : public ReferenceToType {
     391public:
     392        readonly<TraitDecl> base;
     393
     394        TraitInstType(
     395                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    363396        : ReferenceToType( n, q, std::move(as) ), base() {}
    364         UnionInstType( const UnionDecl * b, CV::Qualifiers q = {},
    365                 std::vector<ptr<Attribute>> && as = {} );
    366 
    367         bool isComplete() const override;
    368 
    369         const UnionDecl * aggr() const override { return base; }
    370 
    371         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    372 private:
    373         UnionInstType * clone() const override { return new UnionInstType{ *this }; }
    374         MUTATE_FRIEND
    375 };
    376 
    377 /// instance of enum type
    378 class EnumInstType final : public ReferenceToType {
    379 public:
    380         readonly<EnumDecl> base;
    381 
    382         EnumInstType( const std::string& n, CV::Qualifiers q = {},
    383                 std::vector<ptr<Attribute>> && as = {} )
    384         : ReferenceToType( n, q, std::move(as) ), base() {}
    385         EnumInstType( const EnumDecl * b, CV::Qualifiers q = {},
    386                 std::vector<ptr<Attribute>> && as = {} );
    387 
    388         bool isComplete() const override;
    389 
    390         const EnumDecl * aggr() const override { return base; }
    391 
    392         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    393 private:
    394         EnumInstType * clone() const override { return new EnumInstType{ *this }; }
    395         MUTATE_FRIEND
    396 };
    397 
    398 /// instance of trait type
    399 class TraitInstType final : public ReferenceToType {
    400 public:
    401         readonly<TraitDecl> base;
    402 
    403         TraitInstType( const std::string& n, CV::Qualifiers q = {},
    404                 std::vector<ptr<Attribute>> && as = {} )
    405         : ReferenceToType( n, q, std::move(as) ), base() {}
    406         TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
    407                 std::vector<ptr<Attribute>> && as = {} );
     397
     398        TraitInstType(
     399                const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    408400
    409401        // not meaningful for TraitInstType
     
    424416        TypeDecl::Kind kind;
    425417
    426         TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
     418        TypeInstType(
     419                const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
    427420                std::vector<ptr<Attribute>> && as = {} )
    428421        : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
     
    431424        : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
    432425
     426        TypeInstType( const TypeInstType & o );
     427
    433428        /// sets `base`, updating `kind` correctly
    434429        void set_base( const TypeDecl * );
  • src/AST/TypeEnvironment.cpp

    rdab09ad rfb0ae06  
    5959        std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) );
    6060        out << ")";
    61        
     61
    6262        if ( clz.bound ) {
    6363                out << " -> ";
     
    9292                                }
    9393                        }
    94                        
     94
    9595                        i = next;  // go to next node even if this removed
    9696                }
     
    161161                Pass<Occurs> occur{ var, env };
    162162                maybe_accept( ty, occur );
    163                 return occur.pass.result;
    164         }
    165 }
    166 
    167 bool TypeEnvironment::combine( 
     163                return occur.core.result;
     164        }
     165}
     166
     167bool TypeEnvironment::combine(
    168168                const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) {
    169169        // short-circuit easy cases
     
    199199                                auto st = internal_lookup( *vt );
    200200                                if ( st == env.end() ) {
    201                                         // unbound, safe to add if occurs 
     201                                        // unbound, safe to add if occurs
    202202                                        if ( r.bound && occurs( r.bound, *vt, *this ) ) return false;
    203203                                        r.vars.emplace( *vt );
     
    266266}
    267267
    268 bool TypeEnvironment::bindVar( 
    269                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
    270                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 
    271                 const SymbolTable & symtab 
     268bool TypeEnvironment::bindVar(
     269                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
     270                AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen,
     271                const SymbolTable & symtab
    272272) {
    273273        // remove references from bound type, so that type variables can only bind to value types
     
    286286                        ptr<Type> newType = it->bound;
    287287                        reset_qualifiers( newType, typeInst->qualifiers );
    288                         if ( unifyInexact( 
    289                                         newType, target, *this, need, have, open, 
     288                        if ( unifyInexact(
     289                                        newType, target, *this, need, have, open,
    290290                                        widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) {
    291291                                if ( common ) {
     
    300300                }
    301301        } else {
    302                 env.emplace_back( 
     302                env.emplace_back(
    303303                        typeInst->name, target, widen.first && widen.second, data );
    304304        }
     
    306306}
    307307
    308 bool TypeEnvironment::bindVarToVar( 
    309                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
    310                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 
    311                 WidenMode widen, const SymbolTable & symtab 
     308bool TypeEnvironment::bindVarToVar(
     309                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
     310                AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
     311                WidenMode widen, const SymbolTable & symtab
    312312) {
    313313        auto c1 = internal_lookup( var1->name );
    314314        auto c2 = internal_lookup( var2->name );
    315        
     315
    316316        // exit early if variables already bound together
    317317        if ( c1 != env.end() && c1 == c2 ) {
     
    396396}
    397397
    398 bool TypeEnvironment::mergeBound( 
     398bool TypeEnvironment::mergeBound(
    399399                EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) {
    400400        if ( from.bound ) {
     
    406406                        AssertionSet need, have;
    407407
    408                         if ( unifyInexact( 
     408                        if ( unifyInexact(
    409409                                        toType, fromType, *this, need, have, open, widen, symtab, common ) ) {
    410410                                // unifies, set common type if necessary
     
    424424}
    425425
    426 bool TypeEnvironment::mergeClasses( 
     426bool TypeEnvironment::mergeClasses(
    427427        ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab
    428428) {
  • src/AST/TypeEnvironment.hpp

    rdab09ad rfb0ae06  
    3737/// Adding this comparison operator significantly improves assertion satisfaction run time for
    3838/// some cases. The current satisfaction algorithm's speed partially depends on the order of
    39 /// assertions. Assertions which have fewer possible matches should appear before assertions 
    40 /// which have more possible matches. This seems to imply that this could be further improved 
    41 /// by providing an indexer as an additional argument and ordering based on the number of 
     39/// assertions. Assertions which have fewer possible matches should appear before assertions
     40/// which have more possible matches. This seems to imply that this could be further improved
     41/// by providing an indexer as an additional argument and ordering based on the number of
    4242/// matches of the same kind (object, function) for the names of the declarations.
    4343///
    44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 
     44/// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
    4545/// comparator.
    4646///
    47 /// Note: since this compares pointers for position, minor changes in the source file that 
    48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 
    49 /// placement of a line directive can reorder type pointers with respect to each other so that 
    50 /// assertions are seen in different orders, causing a potentially different number of 
    51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 
    52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 
    53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 
    54 /// name instead of type as the second comparator, but this causes some assertions to never be 
     47/// Note: since this compares pointers for position, minor changes in the source file that
     48/// affect memory layout can alter compilation time in unpredictable ways. For example, the
     49/// placement of a line directive can reorder type pointers with respect to each other so that
     50/// assertions are seen in different orders, causing a potentially different number of
     51/// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27
     52/// seconds by reordering line directives alone, so it would be nice to fix this comparison so
     53/// that assertions compare more consistently. I've tried to modify this to compare on mangle
     54/// name instead of type as the second comparator, but this causes some assertions to never be
    5555/// recorded. More investigation is needed.
    5656struct AssertCompare {
     
    8686void print( std::ostream &, const OpenVarSet &, Indenter indent = {} );
    8787
    88 /// Represents an equivalence class of bound type variables, optionally with the concrete type 
     88/// Represents an equivalence class of bound type variables, optionally with the concrete type
    8989/// they bind to.
    9090struct EqvClass {
     
    9595
    9696        EqvClass() : vars(), bound(), allowWidening( true ), data() {}
    97        
     97
    9898        /// Copy-with-bound constructor
    99         EqvClass( const EqvClass & o, const Type * b ) 
     99        EqvClass( const EqvClass & o, const Type * b )
    100100        : vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {}
    101101
     
    142142        void writeToSubstitution( TypeSubstitution & sub ) const;
    143143
    144         template< typename node_t, enum Node::ref_type ref_t >
    145         int apply( ptr_base< node_t, ref_t > & type ) const {
     144        template< typename node_t >
     145        auto apply( node_t && type ) const {
    146146                TypeSubstitution sub;
    147147                writeToSubstitution( sub );
    148                 return sub.apply( type );
    149         }
    150 
    151         template< typename node_t, enum Node::ref_type ref_t >
    152         int applyFree( ptr_base< node_t, ref_t > & type ) const {
     148                return sub.apply( std::forward<node_t>(type) );
     149        }
     150
     151        template< typename node_t >
     152        auto applyFree( node_t && type ) const {
    153153                TypeSubstitution sub;
    154154                writeToSubstitution( sub );
    155                 return sub.applyFree( type );
     155                return sub.applyFree( std::forward<node_t>(type) );
    156156        }
    157157
     
    172172        void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars );
    173173
    174         /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 
     174        /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if
    175175        /// needed. Returns false on failure.
    176         bool bindVar( 
    177                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
    178                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
     176        bool bindVar(
     177                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
     178                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    179179                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    180        
    181         /// Binds the type classes represented by `var1` and `var2` together; will add one or both 
     180
     181        /// Binds the type classes represented by `var1` and `var2` together; will add one or both
    182182        /// classes if needed. Returns false on failure.
    183         bool bindVarToVar( 
    184                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
    185                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
     183        bool bindVarToVar(
     184                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
     185                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    186186                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    187187
     
    198198
    199199        /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails
    200         bool mergeBound( 
     200        bool mergeBound(
    201201                EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab );
    202202
    203203        /// Merges two type classes from local environment, returning false if fails
    204         bool mergeClasses( 
    205                 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 
     204        bool mergeClasses(
     205                ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars,
    206206                const SymbolTable & symtab );
    207207
  • src/AST/TypeSubstitution.cpp

    rdab09ad rfb0ae06  
    1818
    1919namespace ast {
     20
     21
     22// size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
    2023
    2124TypeSubstitution::TypeSubstitution() {
     
    9295namespace {
    9396        struct EnvTrimmer {
    94                 ptr<TypeSubstitution> env;
     97                const TypeSubstitution * env;
    9598                TypeSubstitution * newEnv;
    9699                EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
     
    108111        if ( env ) {
    109112                TypeSubstitution * newEnv = new TypeSubstitution();
    110 #if TIME_TO_CONVERT_PASSES
    111113                Pass<EnvTrimmer> trimmer( env, newEnv );
    112114                expr->accept( trimmer );
    113 #else
    114                 (void)expr;
    115                 (void)env;
    116 #endif
    117115                return newEnv;
    118116        }
     
    121119
    122120void TypeSubstitution::normalize() {
    123 #if TIME_TO_CONVERT_PASSES
    124         PassVisitor<Substituter> sub( *this, true );
     121        Pass<Substituter> sub( *this, true );
    125122        do {
    126                 sub.pass.subCount = 0;
    127                 sub.pass.freeOnly = true;
     123                sub.core.subCount = 0;
     124                sub.core.freeOnly = true;
    128125                for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
    129                         i->second = i->second->acceptMutator( sub );
    130                 }
    131         } while ( sub.pass.subCount );
    132 #endif
    133 }
    134 
    135 #if TIME_TO_CONVERT_PASSES
    136 
    137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
     126                        i->second = i->second->accept( sub );
     127                }
     128        } while ( sub.core.subCount );
     129}
     130
     131const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
    138132        BoundVarsType::const_iterator bound = boundVars.find( inst->name );
    139133        if ( bound != boundVars.end() ) return inst;
     
    146140                // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
    147141                // TODO: investigate preventing type variables from being bound to themselves in the first place.
    148                 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
     142                if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
    149143                        if ( inst->name == replacement->name ) {
    150144                                return inst;
     
    153147                // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
    154148                subCount++;
    155                 Type * newtype = i->second->clone();
    156                 newtype->get_qualifiers() |= inst->get_qualifiers();
    157                 delete inst;
    158                 // Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
    159                 return newtype->acceptMutator( *visitor );
    160         } // if
    161 }
    162 
    163 Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
     149                ptr<Type> newType = i->second; // force clone if needed
     150                add_qualifiers( newType, inst->qualifiers );
     151                // Note: need to recursively apply substitution to the new type because normalize does not
     152                // substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
     153                newType = newType->accept( *visitor );
     154                return newType.release();
     155        } // if
     156}
     157
     158const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
    164159        VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
    165160        if ( i == sub.varEnv.end() ) {
     
    167162        } else {
    168163                subCount++;
    169                 delete nameExpr;
    170                 return i->second->clone();
    171         } // if
    172 }
    173 
    174 void TypeSubstitution::Substituter::premutate( Type * type ) {
     164                return i->second;
     165        } // if
     166}
     167
     168void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
    175169        GuardValue( boundVars );
    176170        // bind type variables from forall-qualifiers
    177171        if ( freeOnly ) {
    178                 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
    179                         boundVars.insert( (*tyvar)->name );
     172                for ( const TypeDecl * tyvar : ptype->forall ) {
     173                                boundVars.insert( tyvar->name );
    180174                } // for
    181175        } // if
    182176}
    183177
    184 template< typename TypeClass >
    185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
     178void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) {
    186179        GuardValue( boundVars );
    187180        // bind type variables from forall-qualifiers
    188181        if ( freeOnly ) {
    189                 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
    190                         boundVars.insert( (*tyvar)->name );
     182                for ( const TypeDecl * tyvar : type->forall ) {
     183                        boundVars.insert( tyvar->name );
    191184                } // for
    192185                // bind type variables from generic type instantiations
    193                 std::list< TypeDecl* > *baseParameters = type->get_baseParameters();
    194                 if ( baseParameters && ! type->parameters.empty() ) {
    195                         for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) {
    196                                 boundVars.insert( (*tyvar)->name );
    197                         } // for
    198                 } // if
    199         } // if
    200 }
    201 
    202 void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
     186                if ( auto decl = type->aggr() ) {
     187                        if ( ! type->params.empty() ) {
     188                                for ( const TypeDecl * tyvar : decl->params ) {
     189                                        boundVars.insert( tyvar->name );
     190                                } // for
     191                        } // if
     192                }
     193        } // if
     194}
     195
     196void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
    203197        handleAggregateType( aggregateUseType );
    204198}
    205199
    206 void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
     200void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
    207201        handleAggregateType( aggregateUseType );
    208202}
    209 
    210 #endif
    211203
    212204} // namespace ast
  • src/AST/TypeSubstitution.hpp

    rdab09ad rfb0ae06  
    4444        TypeSubstitution &operator=( const TypeSubstitution &other );
    4545
    46         template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const;
    47         template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const;
     46        template< typename SynTreeClass >
     47        struct ApplyResult {
     48                // const SynTreeClass * node;
     49                ast::ptr<SynTreeClass> node;
     50                int count;
     51        };
     52
     53        template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const;
     54        template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const;
    4855
    4956        template< typename node_t, enum Node::ref_type ref_t >
    5057        int apply( ptr_base< node_t, ref_t > & input ) const {
    5158                const node_t * p = input.get();
    52                 int ret = apply(p);
    53                 input = p;
    54                 return ret;
     59                auto ret = apply(p);
     60                input = ret.node;
     61                return ret.count;
    5562        }
    5663
     
    5865        int applyFree( ptr_base< node_t, ref_t > & input ) const {
    5966                const node_t * p = input.get();
    60                 int ret = applyFree(p);
    61                 input = p;
    62                 return ret;
     67                auto ret = applyFree(p);
     68                input = ret.node;
     69                return ret.count;
    6370        }
    6471
     
    9299        void initialize( const TypeSubstitution &src, TypeSubstitution &dest );
    93100
    94         template<typename pass_type>
     101        template<typename core_t>
    95102        friend class Pass;
    96103
     
    147154// PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
    148155#include "Pass.hpp"
     156#include "Copy.hpp"
    149157
    150158namespace ast {
     
    152160// definitition must happen after PassVisitor is included so that WithGuards can be used
    153161struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
     162                static size_t traceId;
    154163
    155164                Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    156165
    157 #if TIME_TO_CONVERT_PASSES
    158 
    159                 Type * postmutate( TypeInstType * aggregateUseType );
    160                 Expression * postmutate( NameExpr * nameExpr );
     166                const Type * postvisit( const TypeInstType * aggregateUseType );
     167                const Expr * postvisit( const NameExpr * nameExpr );
    161168
    162169                /// Records type variable bindings from forall-statements
    163                 void premutate( Type * type );
     170                void previsit( const ParameterizedType * type );
    164171                /// Records type variable bindings from forall-statements and instantiations of generic types
    165                 template< typename TypeClass > void handleAggregateType( TypeClass * type );
    166 
    167                 void premutate( StructInstType * aggregateUseType );
    168                 void premutate( UnionInstType * aggregateUseType );
    169 
    170 #endif
     172                void handleAggregateType( const ReferenceToType * type );
     173
     174                void previsit( const StructInstType * aggregateUseType );
     175                void previsit( const UnionInstType * aggregateUseType );
    171176
    172177                const TypeSubstitution & sub;
     
    179184
    180185template< typename SynTreeClass >
    181 int TypeSubstitution::apply( const SynTreeClass *& input ) const {
     186TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {
    182187        assert( input );
    183188        Pass<Substituter> sub( *this, false );
    184         input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    185 ///     std::cerr << "substitution result is: ";
    186 ///     newType->print( std::cerr );
    187 ///     std::cerr << std::endl;
    188         return sub.pass.subCount;
     189        input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
     190        return { input, sub.core.subCount };
    189191}
    190192
    191193template< typename SynTreeClass >
    192 int TypeSubstitution::applyFree( const SynTreeClass *& input ) const {
     194TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {
    193195        assert( input );
    194196        Pass<Substituter> sub( *this, true );
    195197        input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    196 ///     std::cerr << "substitution result is: ";
    197 ///     newType->print( std::cerr );
    198 ///     std::cerr << std::endl;
    199         return sub.pass.subCount;
     198        return { input, sub.core.subCount };
    200199}
    201200
  • src/AST/module.mk

    rdab09ad rfb0ae06  
    2222        AST/DeclReplacer.cpp \
    2323        AST/Expr.cpp \
     24        AST/ForallSubstitutionTable.cpp \
    2425        AST/GenericSubstitution.cpp \
    2526        AST/Init.cpp \
  • src/AST/porting.md

    rdab09ad rfb0ae06  
    4747      template<typename node_t>
    4848      friend node_t * mutate(const node_t * node);
     49      template<typename node_t>
     50      friend node_t * shallowCopy(const node_t * node);
     51    or equilant.
     52* You should use the `mutate` function where possible as it avoids extra copies.
     53  * If you must copy use `shallowCopy` or `deepCopy` as required.
    4954
    5055All leaves of the `Node` inheritance tree are now declared `final`
  • src/Common/Eval.cc

    rdab09ad rfb0ae06  
    168168        if (expr) {
    169169                expr->accept(ev);
    170                 return std::make_pair(ev.pass.value, ev.pass.valid);
     170                return std::make_pair(ev.core.value, ev.core.valid);
    171171        } else {
    172172                return std::make_pair(0, false);
  • src/Common/ScopedMap.h

    rdab09ad rfb0ae06  
    249249
    250250        /// Gets the note at the given scope
     251        Note& getNote() { return scopes.back().note; }
     252        const Note& getNote() const { return scopes.back().note; }
    251253        Note& getNote( size_type i ) { return scopes[i].note; }
    252254        const Note& getNote( size_type i ) const { return scopes[i].note; }
  • src/Common/Stats/Heap.cc

    rdab09ad rfb0ae06  
    5353                const size_t passes_size = sizeof(passes) / sizeof(passes[0]);
    5454                size_t       passes_cnt = 1;
     55
     56                StatBlock    stacktrace_stats[100];
     57                size_t       stacktrace_stats_count = 0;
     58                bool         stacktrace_stats_enabled = true;
     59
     60                size_t       trace[1000];
     61                const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t);
     62                size_t       stacktrace_depth;
     63
     64                size_t new_stacktrace_id(const char * const name) {
     65                        stacktrace_stats[stacktrace_stats_count].name = name;
     66                        return stacktrace_stats_count++;
     67                }
     68
     69                void stacktrace_push(size_t id) {
     70                        ++stacktrace_depth;
     71                        assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc");
     72                        trace[stacktrace_depth] = id;
     73                }
     74
     75                void stacktrace_pop() {
     76                        assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty");
     77                        --stacktrace_depth;
     78                }
    5579
    5680                void newPass( const char * const name ) {
     
    116140                        for(size_t i = 0; i < passes_cnt; i++) {
    117141                                print(passes[i], nc, total_mallocs, total_frees, overall_peak);
     142                        }
     143
     144                        print('-', nct);
     145                        std::cerr << std::setw(nc) << "Trace";
     146                        std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
     147
     148                        print('-', nct);
     149                        for (size_t i = 0; i < stacktrace_stats_count; i++) {
     150                                print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak);
    118151                        }
    119152                        print('-', nct);
     
    188221                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    189222                                }
     223
     224                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     225                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     226                                }
    190227                                return __malloc( size );
    191228                        }
     
    196233                                        passes[passes_cnt - 1].frees++;
    197234                                        passes[passes_cnt - 1].n_allocs--;
     235                                }
     236                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     237                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
    198238                                }
    199239                                return __free( ptr );
     
    208248                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    209249                                }
     250                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     251                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     252                                }
    210253                                return __calloc( nelem, size );
    211254                        }
     
    218261                                        passes[passes_cnt - 1].frees++;
    219262                                } // if
     263                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     264                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     265                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
     266                                }
    220267                                return s;
    221268                        }
  • src/Common/Stats/Heap.h

    rdab09ad rfb0ae06  
    2020                void newPass( const char * const name );
    2121                void print();
     22
     23                size_t new_stacktrace_id(const char * const name);
     24                void stacktrace_push(size_t id);
     25                void stacktrace_pop();
    2226        }
    2327}
  • src/CompilationState.cc

    rdab09ad rfb0ae06  
    1414//
    1515
     16#include "config.h"
     17
    1618int
    1719        astp = false,
     
    2830        genproto = false,
    2931        deterministic_output = false,
     32        useNewAST = CFA_USE_NEW_AST,
    3033        nomainp = false,
    3134        parsep = false,
  • src/CompilationState.h

    rdab09ad rfb0ae06  
    2929        genproto,
    3030        deterministic_output,
     31        useNewAST,
    3132        nomainp,
    3233        parsep,
  • src/InitTweak/InitTweak.cc

    rdab09ad rfb0ae06  
    127127        ast::Pass< InitFlattener_new > flattener;
    128128        maybe_accept( init, flattener );
    129         return std::move( flattener.pass.argList );
     129        return std::move( flattener.core.argList );
    130130}
    131131
     
    561561                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    562562                maybe_accept( stmt, finder );
    563                 return std::move( finder.pass.matches );
     563                return std::move( finder.core.matches );
    564564        }
    565565
  • src/ResolvExpr/AdjustExprType.cc

    rdab09ad rfb0ae06  
    100100
    101101namespace {
    102         struct AdjustExprType_new final : public ast::WithShortCircuiting {
     102        class AdjustExprType_new final : public ast::WithShortCircuiting {
     103                const ast::SymbolTable & symtab;
     104        public:
    103105                const ast::TypeEnvironment & tenv;
    104                 const ast::SymbolTable & symtab;
    105106
    106107                AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    107                 : tenv( e ), symtab( syms ) {}
     108                : symtab( syms ), tenv( e ) {}
    108109
    109                 void premutate( const ast::VoidType * ) { visit_children = false; }
    110                 void premutate( const ast::BasicType * ) { visit_children = false; }
    111                 void premutate( const ast::PointerType * ) { visit_children = false; }
    112                 void premutate( const ast::ArrayType * ) { visit_children = false; }
    113                 void premutate( const ast::FunctionType * ) { visit_children = false; }
    114                 void premutate( const ast::StructInstType * ) { visit_children = false; }
    115                 void premutate( const ast::UnionInstType * ) { visit_children = false; }
    116                 void premutate( const ast::EnumInstType * ) { visit_children = false; }
    117                 void premutate( const ast::TraitInstType * ) { visit_children = false; }
    118                 void premutate( const ast::TypeInstType * ) { visit_children = false; }
    119                 void premutate( const ast::TupleType * ) { visit_children = false; }
    120                 void premutate( const ast::VarArgsType * ) { visit_children = false; }
    121                 void premutate( const ast::ZeroType * ) { visit_children = false; }
    122                 void premutate( const ast::OneType * ) { visit_children = false; }
     110                void previsit( const ast::VoidType * ) { visit_children = false; }
     111                void previsit( const ast::BasicType * ) { visit_children = false; }
     112                void previsit( const ast::PointerType * ) { visit_children = false; }
     113                void previsit( const ast::ArrayType * ) { visit_children = false; }
     114                void previsit( const ast::FunctionType * ) { visit_children = false; }
     115                void previsit( const ast::StructInstType * ) { visit_children = false; }
     116                void previsit( const ast::UnionInstType * ) { visit_children = false; }
     117                void previsit( const ast::EnumInstType * ) { visit_children = false; }
     118                void previsit( const ast::TraitInstType * ) { visit_children = false; }
     119                void previsit( const ast::TypeInstType * ) { visit_children = false; }
     120                void previsit( const ast::TupleType * ) { visit_children = false; }
     121                void previsit( const ast::VarArgsType * ) { visit_children = false; }
     122                void previsit( const ast::ZeroType * ) { visit_children = false; }
     123                void previsit( const ast::OneType * ) { visit_children = false; }
    123124
    124                 const ast::Type * postmutate( const ast::ArrayType * at ) {
     125                const ast::Type * postvisit( const ast::ArrayType * at ) {
    125126                        return new ast::PointerType{ at->base, at->qualifiers };
    126127                }
    127128
    128                 const ast::Type * postmutate( const ast::FunctionType * ft ) {
     129                const ast::Type * postvisit( const ast::FunctionType * ft ) {
    129130                        return new ast::PointerType{ ft };
    130131                }
    131132
    132                 const ast::Type * postmutate( const ast::TypeInstType * inst ) {
     133                const ast::Type * postvisit( const ast::TypeInstType * inst ) {
    133134                        // replace known function-type-variables with pointer-to-function
    134135                        if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
  • src/ResolvExpr/Candidate.hpp

    rdab09ad rfb0ae06  
    5151
    5252        Candidate( const ast::Expr * x, const ast::TypeEnvironment & e )
    53         : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {}
     53        : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {
     54                assert(x->result);
     55        }
    5456
    5557        Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero )
    5658        : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
    57           need( o.need ) {}
     59          need( o.need ) {
     60                assert(x->result);
     61        }
    5862
    5963        Candidate(
    60                 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
     64                const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
    6165                const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero )
    62         : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {}
     66        : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {
     67                assert(x->result);
     68        }
    6369
    6470        Candidate(
     
    6672                ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero )
    6773        : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ),
    68           need( n.begin(), n.end() ) {}
     74          need( n.begin(), n.end() ) {
     75                assert(x->result);
     76        }
    6977};
    7078
  • src/ResolvExpr/CandidateFinder.cpp

    rdab09ad rfb0ae06  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Wed Jun 5 14:30:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct  1 14:55:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    5454                return new ast::CastExpr{ expr, expr->result->stripReferences() };
    5555        }
    56        
     56
    5757        return expr;
    5858}
     
    6161UniqueId globalResnSlot = 0;
    6262
    63 Cost computeConversionCost( 
    64         const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
    65         const ast::TypeEnvironment & env
     63Cost computeConversionCost(
     64        const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
     65        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    6666) {
    6767        PRINT(
     
    7474                std::cerr << std::endl;
    7575        )
    76         Cost convCost = conversionCost( argType, paramType, symtab, env );
     76        Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env );
    7777        PRINT(
    7878                std::cerr << std::endl << "cost is " << convCost << std::endl;
     
    107107
    108108        /// Computes conversion cost for a given expression to a given type
    109         const ast::Expr * computeExpressionConversionCost( 
    110                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 
     109        const ast::Expr * computeExpressionConversionCost(
     110                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
    111111        ) {
    112                 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env );
     112                Cost convCost = computeConversionCost(
     113                                arg->result, paramType, arg->get_lvalue(), symtab, env );
    113114                outCost += convCost;
    114115
    115                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 
    116                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 
     116                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
     117                // conversion. Ignore poly cost for now, since this requires resolution of the cast to
    117118                // infer parameters and this does not currently work for the reason stated below
    118119                Cost tmpCost = convCost;
     
    123124                        return new ast::CastExpr{ arg, newType };
    124125
    125                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not 
    126                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 
     126                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     127                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
    127128                        // once this is fixed it should be possible to resolve the cast.
    128                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 
    129                         // but it shouldn't be because this makes the conversion from DT* to DT* since 
     129                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
     130                        // but it shouldn't be because this makes the conversion from DT* to DT* since
    130131                        // commontype(zero_t, DT*) is DT*, rather than nothing
    131132
    132133                        // CandidateFinder finder{ symtab, env };
    133134                        // finder.find( arg, ResolvMode::withAdjustment() );
    134                         // assertf( finder.candidates.size() > 0, 
     135                        // assertf( finder.candidates.size() > 0,
    135136                        //      "Somehow castable expression failed to find alternatives." );
    136                         // assertf( finder.candidates.size() == 1, 
     137                        // assertf( finder.candidates.size() == 1,
    137138                        //      "Somehow got multiple alternatives for known cast expression." );
    138139                        // return finder.candidates.front()->expr;
     
    143144
    144145        /// Computes conversion cost for a given candidate
    145         Cost computeApplicationConversionCost( 
    146                 CandidateRef cand, const ast::SymbolTable & symtab 
     146        Cost computeApplicationConversionCost(
     147                CandidateRef cand, const ast::SymbolTable & symtab
    147148        ) {
    148149                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     
    167168                                if ( function->isVarArgs ) {
    168169                                        convCost.incUnsafe();
    169                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 
     170                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
    170171                                                << convCost << std::endl; ; )
    171172                                        // convert reference-typed expressions into value-typed expressions
    172                                         cand->expr = ast::mutate_field_index( 
    173                                                 appExpr, &ast::ApplicationExpr::args, i, 
     173                                        cand->expr = ast::mutate_field_index(
     174                                                appExpr, &ast::ApplicationExpr::args, i,
    174175                                                referenceToRvalueConversion( args[i], convCost ) );
    175176                                        continue;
     
    180181                                // Default arguments should be free - don't include conversion cost.
    181182                                // Unwrap them here because they are not relevant to the rest of the system
    182                                 cand->expr = ast::mutate_field_index( 
     183                                cand->expr = ast::mutate_field_index(
    183184                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
    184185                                ++param;
     
    188189                        // mark conversion cost and also specialization cost of param type
    189190                        const ast::Type * paramType = (*param)->get_type();
    190                         cand->expr = ast::mutate_field_index( 
    191                                 appExpr, &ast::ApplicationExpr::args, i, 
    192                                 computeExpressionConversionCost( 
     191                        cand->expr = ast::mutate_field_index(
     192                                appExpr, &ast::ApplicationExpr::args, i,
     193                                computeExpressionConversionCost(
    193194                                        args[i], paramType, symtab, cand->env, convCost ) );
    194195                        convCost.decSpec( specCost( paramType ) );
     
    198199                if ( param != params.end() ) return Cost::infinity;
    199200
    200                 // specialization cost of return types can't be accounted for directly, it disables 
     201                // specialization cost of return types can't be accounted for directly, it disables
    201202                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    202203                //
     
    215216        }
    216217
    217         void makeUnifiableVars( 
    218                 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 
    219                 ast::AssertionSet & need 
     218        void makeUnifiableVars(
     219                const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
     220                ast::AssertionSet & need
    220221        ) {
    221222                for ( const ast::TypeDecl * tyvar : type->forall ) {
     
    254255
    255256                ArgPack()
    256                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 
     257                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
    257258                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    258                
    259                 ArgPack( 
    260                         const ast::TypeEnvironment & env, const ast::AssertionSet & need, 
     259
     260                ArgPack(
     261                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    261262                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
    262                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 
     263                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    263264                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    264                
     265
    265266                ArgPack(
    266                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 
    267                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 
    268                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 
     267                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     268                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     269                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    269270                        unsigned nextExpl = 0, unsigned explAlt = 0 )
    270271                : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ),
    271272                  have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    272273                  nextExpl( nextExpl ), explAlt( explAlt ) {}
    273                
     274
    274275                ArgPack(
    275                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 
     276                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
    276277                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    277                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 
    278                   need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 
     278                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),
     279                  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ),
    279280                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    280                
     281
    281282                /// true if this pack is in the middle of an exploded argument
    282283                bool hasExpl() const { return nextExpl > 0; }
     
    286287                        return args[ nextArg-1 ][ explAlt ];
    287288                }
    288                
     289
    289290                /// Ends a tuple expression, consolidating the appropriate args
    290291                void endTuple( const std::vector< ArgPack > & packs ) {
     
    307308
    308309        /// Instantiates an argument to match a parameter, returns false if no matching results left
    309         bool instantiateArgument( 
    310                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 
    311                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 
    312                 unsigned nTuples = 0 
     310        bool instantiateArgument(
     311                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
     312                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
     313                unsigned nTuples = 0
    313314        ) {
    314315                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     
    318319                                // xxx - dropping initializer changes behaviour from previous, but seems correct
    319320                                // ^^^ need to handle the case where a tuple has a default argument
    320                                 if ( ! instantiateArgument( 
     321                                if ( ! instantiateArgument(
    321322                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    322323                                nTuples = 0;
     
    329330                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    330331                        // paramType is a ttype, consumes all remaining arguments
    331                        
     332
    332333                        // completed tuples; will be spliced to end of results to finish
    333334                        std::vector< ArgPack > finalResults{};
     
    342343                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
    343344                                        unsigned nextArg = results[i].nextArg;
    344                                        
     345
    345346                                        // use next element of exploded tuple if present
    346347                                        if ( results[i].hasExpl() ) {
     
    352353                                                results.emplace_back(
    353354                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    354                                                         copy( results[i].need ), copy( results[i].have ), 
     355                                                        copy( results[i].need ), copy( results[i].have ),
    355356                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    356357                                                        results[i].explAlt );
     
    370371                                                        // push empty tuple expression
    371372                                                        newResult.parent = i;
    372                                                         std::vector< ast::ptr< ast::Expr > > emptyList;
    373                                                         newResult.expr =
    374                                                                 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) };
     373                                                        newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
    375374                                                        argType = newResult.expr->result;
    376375                                                } else {
     
    400399
    401400                                                // check unification for ttype before adding to final
    402                                                 if ( 
    403                                                         unify( 
     401                                                if (
     402                                                        unify(
    404403                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
    405                                                                 newResult.open, symtab ) 
     404                                                                newResult.open, symtab )
    406405                                                ) {
    407406                                                        finalResults.emplace_back( move( newResult ) );
     
    424423                                                if ( expl.exprs.empty() ) {
    425424                                                        results.emplace_back(
    426                                                                 results[i], move( env ), copy( results[i].need ), 
     425                                                                results[i], move( env ), copy( results[i].need ),
    427426                                                                copy( results[i].have ), move( open ), nextArg + 1, expl.cost );
    428                                                        
     427
    429428                                                        continue;
    430429                                                }
     
    432431                                                // add new result
    433432                                                results.emplace_back(
    434                                                         i, expl.exprs.front(), move( env ), copy( results[i].need ), 
    435                                                         copy( results[i].have ), move( open ), nextArg + 1, nTuples, 
     433                                                        i, expl.exprs.front(), move( env ), copy( results[i].need ),
     434                                                        copy( results[i].have ), move( open ), nextArg + 1, nTuples,
    436435                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    437436                                        }
     
    479478
    480479                                        results.emplace_back(
    481                                                 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 
     480                                                i, expr, move( env ), move( need ), move( have ), move( open ), nextArg,
    482481                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
    483482                                }
     
    495494                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    496495                                                results.emplace_back(
    497                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 
     496                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),
    498497                                                        move( need ), move( have ), move( open ), nextArg, nTuples );
    499498                                        }
     
    517516                                if ( expl.exprs.empty() ) {
    518517                                        results.emplace_back(
    519                                                 results[i], move( env ), move( need ), move( have ), move( open ), 
     518                                                results[i], move( env ), move( need ), move( have ), move( open ),
    520519                                                nextArg + 1, expl.cost );
    521                                        
     520
    522521                                        continue;
    523522                                }
     
    539538                                        // add new result
    540539                                        results.emplace_back(
    541                                                 i, expr, move( env ), move( need ), move( have ), move( open ), 
     540                                                i, expr, move( env ), move( need ), move( have ), move( open ),
    542541                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    543542                                }
     
    548547                genStart = genEnd;
    549548
    550                 return genEnd != results.size();
     549                return genEnd != results.size();  // were any new results added?
    551550        }
    552551
    553552        /// Generate a cast expression from `arg` to `toType`
    554         const ast::Expr * restructureCast( 
     553        const ast::Expr * restructureCast(
    555554                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    556555        ) {
    557                 if ( 
    558                         arg->result->size() > 1 
    559                         && ! toType->isVoid() 
    560                         && ! dynamic_cast< const ast::ReferenceType * >( toType ) 
     556                if (
     557                        arg->result->size() > 1
     558                        && ! toType->isVoid()
     559                        && ! dynamic_cast< const ast::ReferenceType * >( toType )
    561560                ) {
    562                         // Argument is a tuple and the target type is neither void nor a reference. Cast each 
    563                         // member of the tuple to its corresponding target type, producing the tuple of those 
    564                         // cast expressions. If there are more components of the tuple than components in the 
    565                         // target type, then excess components do not come out in the result expression (but 
     561                        // Argument is a tuple and the target type is neither void nor a reference. Cast each
     562                        // member of the tuple to its corresponding target type, producing the tuple of those
     563                        // cast expressions. If there are more components of the tuple than components in the
     564                        // target type, then excess components do not come out in the result expression (but
    566565                        // UniqueExpr ensures that the side effects will still be produced)
    567566                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    568                                 // expressions which may contain side effects require a single unique instance of 
     567                                // expressions which may contain side effects require a single unique instance of
    569568                                // the expression
    570569                                arg = new ast::UniqueExpr{ arg->location, arg };
     
    574573                                // cast each component
    575574                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    576                                 components.emplace_back( 
     575                                components.emplace_back(
    577576                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    578577                        }
     
    594593
    595594        /// Actually visits expressions to find their candidate interpretations
    596         struct Finder final : public ast::WithShortCircuiting {
     595        class Finder final : public ast::WithShortCircuiting {
     596                const ast::SymbolTable & symtab;
     597        public:
     598                static size_t traceId;
    597599                CandidateFinder & selfFinder;
    598                 const ast::SymbolTable & symtab;
    599600                CandidateList & candidates;
    600601                const ast::TypeEnvironment & tenv;
    601602                ast::ptr< ast::Type > & targetType;
    602603
     604                enum Errors {
     605                        NotFound,
     606                        NoMatch,
     607                        ArgsToFew,
     608                        ArgsToMany,
     609                        RetsToFew,
     610                        RetsToMany,
     611                        NoReason
     612                };
     613
     614                struct {
     615                        Errors code = NotFound;
     616                } reason;
     617
    603618                Finder( CandidateFinder & f )
    604                 : selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),
     619                : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),
    605620                  targetType( f.targetType ) {}
    606                
     621
    607622                void previsit( const ast::Node * ) { visit_children = false; }
    608623
     
    611626                void addCandidate( Args &&... args ) {
    612627                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
     628                        reason.code = NoReason;
    613629                }
    614630
     
    639655
    640656                /// Completes a function candidate with arguments located
    641                 void validateFunctionCandidate( 
    642                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 
    643                         CandidateList & out 
     657                void validateFunctionCandidate(
     658                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     659                        CandidateList & out
    644660                ) {
    645                         ast::ApplicationExpr * appExpr = 
     661                        ast::ApplicationExpr * appExpr =
    646662                                new ast::ApplicationExpr{ func->expr->location, func->expr };
    647663                        // sum cost and accumulate arguments
     
    657673                        appExpr->args = move( vargs );
    658674                        // build and validate new candidate
    659                         auto newCand = 
     675                        auto newCand =
    660676                                std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    661677                        PRINT(
     
    669685                /// Builds a list of candidates for a function, storing them in out
    670686                void makeFunctionCandidates(
    671                         const CandidateRef & func, const ast::FunctionType * funcType, 
     687                        const CandidateRef & func, const ast::FunctionType * funcType,