Changeset 2b4daf2 for src


Ignore:
Timestamp:
Jan 7, 2021, 5:06:22 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
5ad381b
Parents:
42f6e07 (diff), 58fe85a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Location:
src
Files:
3 deleted
40 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Convert.cpp

    r42f6e07 r2b4daf2  
    205205                ftype->parameters = get<DeclarationWithType>().acceptL(node->params);
    206206
    207                 ftype->forall = get<TypeDecl>().acceptL( node->type->forall );
     207                ftype->forall = get<TypeDecl>().acceptL( node->type_params );
     208                if (!node->assertions.empty()) {
     209                        assert(!ftype->forall.empty());
     210                        // find somewhere to place assertions back, for convenience it is the last slot
     211                        ftype->forall.back()->assertions = get<DeclarationWithType>().acceptL(node->assertions);
     212                }
    208213
    209214                visitType(node->type, ftype);
     
    602607
    603608                for (decltype(src->begin()) src_i = src->begin(); src_i != src->end(); src_i++) {
    604                         rslt->add( src_i->first,
     609                        rslt->add( src_i->first.typeString(),
    605610                                   get<Type>().accept1(src_i->second) );
    606                 }
    607 
    608                 for (decltype(src->beginVar()) src_i = src->beginVar(); src_i != src->endVar(); src_i++) {
    609                         rslt->addVar( src_i->first,
    610                                       get<Expression>().accept1(src_i->second) );
    611611                }
    612612
     
    12121212                // ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
    12131213                // ty->parameters = get<DeclarationWithType>().acceptL( node->params );
    1214                 ty->forall = get<TypeDecl>().acceptL( node->forall );
     1214
     1215                auto types = get<TypeInstType>().acceptL( node->forall );
     1216                for (auto t : types) {
     1217                        auto newT = new TypeDecl(*t->baseType);
     1218                        newT->name = t->name; // converted by typeString()
     1219                        for (auto asst : newT->assertions) delete asst;
     1220                        newT->assertions.clear();
     1221                        ty->forall.push_back(newT);
     1222                }
     1223                auto assts = get<VariableExpr>().acceptL( node->assertions );
     1224                if (!assts.empty()) {
     1225                        assert(!types.empty());
     1226                        for (auto asst : assts) {
     1227                                auto newDecl = new ObjectDecl(*strict_dynamic_cast<ObjectDecl*>(asst->var));
     1228                                delete newDecl->type;
     1229                                newDecl->type = asst->result->clone();
     1230                                newDecl->storageClasses.is_extern = true; // hack
     1231                                ty->forall.back()->assertions.push_back(newDecl);
     1232                        }
     1233                }
     1234
    12151235                return visitType( node, ty );
    12161236        }
     
    12991319                        ty = new TypeInstType{
    13001320                                cv( node ),
    1301                                 node->name,
     1321                                node->typeString(),
    13021322                                get<TypeDecl>().accept1( node->base ),
    13031323                                get<Attribute>().acceptL( node->attributes )
     
    13061326                        ty = new TypeInstType{
    13071327                                cv( node ),
    1308                                 node->name,
     1328                                node->typeString(),
    13091329                                node->kind == ast::TypeDecl::Ftype,
    13101330                                get<Attribute>().acceptL( node->attributes )
     
    14311451        /// at conversion stage, all created nodes are guaranteed to be unique, therefore
    14321452        /// const_casting out of smart pointers is permitted.
    1433         std::unordered_map< const BaseSyntaxNode *, ast::ptr<ast::Node> > cache = {};
     1453        std::unordered_map< const BaseSyntaxNode *, ast::readonly<ast::Node> > cache = {};
    14341454
    14351455        // Local Utilities:
     
    15651585                // can function type have attributes? seems not to be the case.
    15661586                // visitType(old->type, ftype);
     1587
     1588                // collect assertions and put directly in FunctionDecl
     1589                std::vector<ast::ptr<ast::DeclWithType>> assertions;
     1590                for (auto & param: forall) {
     1591                        for (auto & asst: param->assertions) {
     1592                                assertf(asst->unique(), "newly converted decl must be unique");
     1593                                assertions.emplace_back(asst);
     1594                        }
     1595                        auto mut = param.get_and_mutate();
     1596                        assertf(mut == param, "newly converted decl must be unique");
     1597                        mut->assertions.clear();
     1598                }
    15671599
    15681600                auto decl = new ast::FunctionDecl{
     
    15841616                cache.emplace( old, decl );
    15851617
     1618                decl->assertions = std::move(assertions);
    15861619                decl->withExprs = GET_ACCEPT_V(withExprs, Expr);
    15871620                decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
     
    20662099        }
    20672100
     2101        // TypeSubstitution shouldn't exist yet in old.
    20682102        ast::TypeSubstitution * convertTypeSubstitution(const TypeSubstitution * old) {
    2069 
     2103               
    20702104                if (!old) return nullptr;
    2071 
     2105                if (old->empty()) return nullptr;
     2106                assert(false);
     2107
     2108                /*
    20722109                ast::TypeSubstitution *rslt = new ast::TypeSubstitution();
    20732110
     
    20772114                }
    20782115
    2079                 for (decltype(old->beginVar()) old_i = old->beginVar(); old_i != old->endVar(); old_i++) {
    2080                         rslt->addVar( old_i->first,
    2081                                       getAccept1<ast::Expr>(old_i->second) );
    2082                 }
    2083 
    20842116                return rslt;
     2117                */
    20852118        }
    20862119
     
    26102643                        ty->params.emplace_back(v->get_type());
    26112644                }
    2612                 ty->forall = GET_ACCEPT_V( forall, TypeDecl );
     2645                // xxx - when will this be non-null?
     2646                // will have to create dangling (no-owner) decls to be pointed to
     2647                auto foralls = GET_ACCEPT_V( forall, TypeDecl );
     2648
     2649                for (auto & param : foralls) {
     2650                        ty->forall.emplace_back(new ast::TypeInstType(param->name, param));
     2651                        for (auto asst : param->assertions) {
     2652                                ty->assertions.emplace_back(new ast::VariableExpr({}, asst));
     2653                        }
     2654                }
    26132655                visitType( old, ty );
    26142656        }
  • src/AST/Decl.cpp

    r42f6e07 r2b4daf2  
    5050
    5151FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
    52                 std::vector<ptr<TypeDecl>>&& forall,
    53                 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    54                 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    55                 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
    56         : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
    57           stmts( stmts ) {
    58                   FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
    59                   for (auto & param : this->params) {
    60                           ftype->params.emplace_back(param->get_type());
    61                   }
    62                   for (auto & ret : this->returns) {
    63                           ftype->returns.emplace_back(ret->get_type());
    64                   }
    65                   ftype->forall = std::move(forall);
    66                   this->type = ftype;
    67           }
     52        std::vector<ptr<TypeDecl>>&& forall,
     53        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     54        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
     55        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     56: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
     57        type_params(std::move(forall)), stmts( stmts ) {
     58        FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
     59        for (auto & param : this->params) {
     60                ftype->params.emplace_back(param->get_type());
     61        }
     62        for (auto & ret : this->returns) {
     63                ftype->returns.emplace_back(ret->get_type());
     64        }
     65        for (auto & tp : this->type_params) {
     66                ftype->forall.emplace_back(new TypeInstType(tp->name, tp));
     67        }
     68        this->type = ftype;
     69}
    6870
    6971
  • src/AST/Decl.hpp

    r42f6e07 r2b4daf2  
    127127        std::vector<ptr<DeclWithType>> params;
    128128        std::vector<ptr<DeclWithType>> returns;
     129        std::vector<ptr<TypeDecl>> type_params;
     130        std::vector<ptr<DeclWithType>> assertions;
    129131        // declared type, derived from parameter declarations
    130132        ptr<FunctionType> type;
    131133        ptr<CompoundStmt> stmts;
    132134        std::vector< ptr<Expr> > withExprs;
     135
    133136
    134137        FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
  • src/AST/Expr.cpp

    r42f6e07 r2b4daf2  
    206206        assert( aggregate->result );
    207207
    208         // Deep copy on result type avoids mutation on transitively multiply referenced object.
    209         //
    210         // Example, adapted from parts of builtins and bootloader:
    211         //
    212         // forall(dtype T)
    213         // struct __Destructor {
    214         //   T * object;
    215         //   void (*dtor)(T *);
    216         // };
    217         //
    218         // forall(dtype S)
    219         // void foo(__Destructor(S) &d) {
    220         //   if (d.dtor) {  // here
    221         //   }
    222         // }
    223         //
    224         // Let e be the "d.dtor" guard espression, which is MemberExpr after resolve.  Let d be the
    225         // declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level
    226         // declaration of __Destructor.  Consider the types e.result and d.type.  In the old AST, one
    227         // is a clone of the other.  Ordinary new-AST use would set them up as a multiply-referenced
    228         // object.
    229         //
    230         // e.result: PointerType
    231         // .base: FunctionType
    232         // .params.front(): ObjectDecl, the anonymous parameter of type T*
    233         // .type: PointerType
    234         // .base: TypeInstType
    235         // let x = that
    236         // let y = similar, except start from d.type
    237         //
    238         // Consider two code lines down, genericSubstitution(...).apply(result).
    239         //
    240         // Applying this chosen-candidate's type substitution means modifying x, substituting
    241         // S for T.  This mutation should affect x and not y.
    242 
    243         result = deepCopy(mem->get_type());
     208        result = mem->get_type();
    244209
    245210        // substitute aggregate generic parameters into member type
  • src/AST/Node.hpp

    r42f6e07 r2b4daf2  
    229229        const node_t & operator* () const { _check(); return *node; }
    230230        explicit operator bool() const { _check(); return node; }
    231         operator const node_t * () const { _check(); return node; }
     231        operator const node_t * () const & { _check(); return node; }
     232        operator const node_t * () && = delete;
    232233
    233234        const node_t * release() {
  • src/AST/Pass.hpp

    r42f6e07 r2b4daf2  
    3434
    3535#include "AST/SymbolTable.hpp"
    36 
    37 #include "AST/ForallSubstitutionTable.hpp"
    3836
    3937// Private prelude header, needed for some of the magic tricks this class pulls off
     
    6664// | WithVisitorRef        - provides an pointer to the templated visitor wrapper
    6765// | WithSymbolTable       - provides symbol table functionality
    68 // | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
    6966//
    7067// Other Special Members:
     
    258255        container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    259256
    260         /// Mutate forall-list, accounting for presence of type substitution map
    261         template<typename node_t>
    262         void mutate_forall( const node_t *& );
    263 
    264257public:
    265258        /// Logic to call the accept and mutate the parent if needed, delegates call to accept
     
    398391};
    399392
    400 /// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
    401 struct WithForallSubstitutor {
    402         ForallSubstitutionTable subs;
    403 };
    404 
    405393}
    406394
  • src/AST/Pass.impl.hpp

    r42f6e07 r2b4daf2  
    367367        }
    368368
    369 
    370         template< typename core_t >
    371         template< typename node_t >
    372         void ast::Pass< core_t >::mutate_forall( const node_t *& node ) {
    373                 if ( auto subs = __pass::forall::subs( core, 0 ) ) {
    374                         // tracking TypeDecl substitution, full clone
    375                         if ( node->forall.empty() ) return;
    376 
    377                         node_t * mut = __pass::mutate<core_t>( node );
    378                         mut->forall = subs->clone( node->forall, *this );
    379                         node = mut;
    380                 } else {
    381                         // not tracking TypeDecl substitution, just mutate
    382                         maybe_accept( node, &node_t::forall );
    383                 }
    384         }
    385369}
    386370
     
    504488                        __pass::symtab::addId( core, 0, func );
    505489                        VISIT(
    506                                 // parameter declarations are now directly here
     490                                // parameter declarations
    507491                                maybe_accept( node, &FunctionDecl::params );
    508492                                maybe_accept( node, &FunctionDecl::returns );
    509                                 // foralls are still in function type
    510                                 maybe_accept( node, &FunctionDecl::type );
     493                                // type params and assertions
     494                                maybe_accept( node, &FunctionDecl::type_params );
     495                                maybe_accept( node, &FunctionDecl::assertions );
    511496                                // First remember that we are now within a function.
    512497                                ValueGuard< bool > oldInFunction( inFunction );
     
    17581743
    17591744        VISIT({
    1760                 guard_forall_subs forall_guard { *this, node };
    1761                 mutate_forall( node );
     1745                // guard_forall_subs forall_guard { *this, node };
     1746                // mutate_forall( node );
     1747                maybe_accept( node, &FunctionType::assertions );
    17621748                maybe_accept( node, &FunctionType::returns );
    17631749                maybe_accept( node, &FunctionType::params  );
     
    19811967                {
    19821968                        bool mutated = false;
    1983                         std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
     1969                        std::unordered_map< ast::TypeInstType::TypeEnvKey, ast::ptr< ast::Type > > new_map;
    19841970                        for ( const auto & p : node->typeEnv ) {
    19851971                                guard_symtab guard { *this };
     
    19941980                        }
    19951981                }
    1996 
    1997                 {
    1998                         bool mutated = false;
    1999                         std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
    2000                         for ( const auto & p : node->varEnv ) {
    2001                                 guard_symtab guard { *this };
    2002                                 auto new_node = p.second->accept( *this );
    2003                                 if (new_node != p.second) mutated = true;
    2004                                 new_map.insert({ p.first, new_node });
    2005                         }
    2006                         if (mutated) {
    2007                                 auto new_node = __pass::mutate<core_t>( node );
    2008                                 new_node->varEnv.swap( new_map );
    2009                                 node = new_node;
    2010                         }
    2011                 }
    20121982        )
    20131983
  • src/AST/Pass.proto.hpp

    r42f6e07 r2b4daf2  
    413413                static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
    414414
    415                 // Get the substitution table, if present
    416                 template<typename core_t>
    417                 static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) {
    418                         return &core.subs;
    419                 }
    420 
    421                 template<typename core_t>
    422                 static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; }
    423 
    424415                // Replaces a TypeInstType's base TypeDecl according to the table
    425416                template<typename core_t>
  • src/AST/Print.cpp

    r42f6e07 r2b4daf2  
    155155        }
    156156
     157        void print( const ast::FunctionType::AssertionList & assts ) {
     158                if (assts.empty()) return;
     159                os << "with assertions" << endl;
     160                ++indent;
     161                printAll(assts);
     162                os << indent;
     163                --indent;
     164        }
     165
    157166        void print( const std::vector<ptr<Attribute>> & attrs ) {
    158167                if ( attrs.empty() ) return;
     
    206215        void preprint( const ast::NamedTypeDecl * node ) {
    207216                if ( ! node->name.empty() ) {
    208                         if( deterministic_output && isUnboundType(node->name) ) os << "[unbound]:";
    209                         else os << node->name << ": ";
     217                        os << node->name << ": ";
    210218                }
    211219
     
    261269        void preprint( const ast::FunctionType * node ) {
    262270                print( node->forall );
     271                print( node->assertions );
    263272                print( node->qualifiers );
    264273        }
     
    13751384        virtual const ast::Type * visit( const ast::TypeInstType * node ) override final {
    13761385                preprint( node );
    1377                 const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->name;
     1386                const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->typeString();
    13781387                os << "instance of type " << _name
    13791388                   << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)";
     
    15021511                os << indent << "Types:" << endl;
    15031512                for ( const auto& i : *node ) {
    1504                         os << indent+1 << i.first << " -> ";
     1513                        os << indent+1 << i.first.typeString() << " -> ";
    15051514                        indent += 2;
    15061515                        safe_print( i.second );
    1507                         indent -= 2;
    1508                         os << endl;
    1509                 }
    1510                 os << indent << "Non-types:" << endl;
    1511                 for ( auto i = node->beginVar(); i != node->endVar(); ++i ) {
    1512                         os << indent+1 << i->first << " -> ";
    1513                         indent += 2;
    1514                         safe_print( i->second );
    15151516                        indent -= 2;
    15161517                        os << endl;
  • src/AST/SymbolTable.cpp

    r42f6e07 r2b4daf2  
    414414
    415415void SymbolTable::addFunction( const FunctionDecl * func ) {
    416         addTypes( func->type->forall );
     416        for (auto & td : func->type_params) {
     417                addType(td);
     418        }
     419        for (auto & asst : func->assertions) {
     420                addId(asst);
     421        }
     422        // addTypes( func->type->forall );
    417423        addIds( func->returns );
    418424        addIds( func->params );
  • src/AST/Type.cpp

    r42f6e07 r2b4daf2  
    2121
    2222#include "Decl.hpp"
    23 #include "ForallSubstitutor.hpp" // for substituteForall
    2423#include "Init.hpp"
    2524#include "Common/utility.h"      // for copy, move
     
    9291// GENERATED END
    9392
    94 // --- ParameterizedType
    95 
    96 void FunctionType::initWithSub(
    97         const FunctionType & o, Pass< ForallSubstitutor > & sub
    98 ) {
    99         forall = sub.core( o.forall );
    100 }
    101 
    10293// --- FunctionType
    103 
    104 
    105 FunctionType::FunctionType( const FunctionType & o )
    106 : Type( o.qualifiers, copy( o.attributes ) ), returns(), params(),
    107   isVarArgs( o.isVarArgs ) {
    108         Pass< ForallSubstitutor > sub;
    109         initWithSub( o, sub );           // initialize substitution map
    110         returns = sub.core( o.returns ); // apply to return and parameter types
    111         params = sub.core( o.params );
    112 }
    113 
    11494namespace {
    11595        bool containsTtype( const std::vector<ptr<Type>> & l ) {
     
    199179                // TODO: once TypeInstType representation is updated, it should properly check
    200180                // if the context id is filled. this is a temporary hack for now
    201                 return isUnboundType(typeInst->name);
    202         }
    203         return false;
    204 }
    205 
    206 bool isUnboundType(const std::string & tname) {
    207         // xxx - look for a type name produced by renameTyVars.
    208 
    209         // TODO: once TypeInstType representation is updated, it should properly check
    210         // if the context id is filled. this is a temporary hack for now
    211         if (std::count(tname.begin(), tname.end(), '_') >= 3) {
    212                 return true;
     181                return typeInst->formal_usage > 0;
    213182        }
    214183        return false;
  • src/AST/Type.hpp

    r42f6e07 r2b4daf2  
    3636
    3737template< typename T > class Pass;
    38 
    39 struct ForallSubstitutor;
    4038
    4139class Type : public Node {
     
    272270/// Type of a function `[R1, R2](*)(P1, P2, P3)`
    273271class FunctionType final : public Type {
    274         protected:
    275         /// initializes forall with substitutor
    276         void initWithSub( const FunctionType & o, Pass< ForallSubstitutor > & sub );
    277 public:
    278         using ForallList = std::vector<ptr<TypeDecl>>;
     272public:
     273        using ForallList = std::vector<ptr<TypeInstType>>;
     274        using AssertionList = std::vector<ptr<VariableExpr>>;
    279275        ForallList forall;
     276        AssertionList assertions;
    280277
    281278        std::vector<ptr<Type>> returns;
     
    292289        : Type(q), returns(), params(), isVarArgs(va) {}
    293290
    294         FunctionType( const FunctionType & o );
     291        FunctionType( const FunctionType & o ) = default;
    295292
    296293        /// true if either the parameters or return values contain a tttype
     
    397394public:
    398395        readonly<TypeDecl> base;
     396        // previously from renameTyVars; now directly use integer fields instead of synthesized strings
     397        // a nonzero value of formal_usage indicates a formal type (only used in function type)
     398        // a zero value of formal_usage indicates an actual type (referenced inside body of parametric structs and functions)
    399399        TypeDecl::Kind kind;
     400        int formal_usage = 0;
     401        int expr_id = 0;
     402
     403        // compact representation used for map lookups.
     404        struct TypeEnvKey {
     405                const TypeDecl * base;
     406                int formal_usage;
     407                int expr_id;
     408
     409                TypeEnvKey() = default;
     410                TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0): base(base), formal_usage(formal_usage), expr_id(expr_id) {}
     411                TypeEnvKey(const TypeInstType & inst): base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
     412                std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; }
     413                bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
     414
     415        };
     416
     417        bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
    400418
    401419        TypeInstType(
     
    409427        TypeInstType( const TypeInstType & o ) = default;
    410428
     429        TypeInstType( const TypeEnvKey & key )
     430        : BaseInstType(key.base->name), base(key.base), kind(key.base->kind), formal_usage(key.formal_usage), expr_id(key.expr_id) {}
     431
    411432        /// sets `base`, updating `kind` correctly
    412433        void set_base( const TypeDecl * );
     
    418439
    419440        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     441
     442        std::string typeString() const {
     443                if (formal_usage > 0) return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + name;
     444                else return name;
     445        }
    420446private:
    421447        TypeInstType * clone() const override { return new TypeInstType{ *this }; }
     
    510536
    511537bool isUnboundType(const Type * type);
    512 bool isUnboundType(const std::string & tname);
    513 
     538
     539}
     540
     541namespace std {
     542        template<>
     543        struct hash<typename ast::TypeInstType::TypeEnvKey> {
     544                size_t operator() (const ast::TypeInstType::TypeEnvKey & x) const {
     545                        const size_t p = 1000007;
     546                        size_t res = reinterpret_cast<size_t>(x.base);
     547                        res = p * res + x.formal_usage;
     548                        res = p * res + x.expr_id;
     549                        return res;
     550                }
     551        };
    514552}
    515553
  • src/AST/TypeEnvironment.cpp

    r42f6e07 r2b4daf2  
    5252        for ( const auto & i : open ) {
    5353                if ( first ) { first = false; } else { out << ' '; }
    54                 out << i.first << "(" << i.second << ")";
     54                out << i.first.typeString() << "(" << i.second << ")";
    5555        }
    5656}
     
    6262                if(first) first = false;
    6363                else out << " ";
    64                 if( deterministic_output && isUnboundType(var) ) out << "[unbound]";
    65                 else out << var;
     64
     65                if( deterministic_output ) out << "[unbound]";
     66                else out << "_" << var.formal_usage << "_" << var.expr_id << "_";
     67
     68                out << var.base->name;
    6669        }
    6770        out << ")";
     
    7982}
    8083
    81 const EqvClass * TypeEnvironment::lookup( const std::string & var ) const {
     84const EqvClass * TypeEnvironment::lookup( const TypeInstType::TypeEnvKey & var ) const {
    8285        for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) {
    8386                if ( i->vars.find( var ) != i->vars.end() ) return &*i;
     
    106109
    107110void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) {
    108         for ( const TypeDecl * tyDecl : tyDecls ) {
     111        for ( auto & tyDecl : tyDecls ) {
    109112                env.emplace_back( tyDecl );
    110113        }
     
    119122void TypeEnvironment::writeToSubstitution( TypeSubstitution & sub ) const {
    120123        for ( const auto & clz : env ) {
    121                 std::string clzRep;
     124                TypeInstType::TypeEnvKey clzRep;
     125                bool first = true;
    122126                for ( const auto & var : clz.vars ) {
    123127                        if ( clz.bound ) {
    124128                                sub.add( var, clz.bound );
    125                         } else if ( clzRep.empty() ) {
     129                        } else if ( first ) {
    126130                                clzRep = var;
     131                                first = false;
    127132                        } else {
    128                                 sub.add( var, new TypeInstType{ clzRep, clz.data.kind } );
     133                                sub.add( var, new TypeInstType{ clzRep } );
    129134                        }
    130135                }
     
    141146        struct Occurs : public ast::WithVisitorRef<Occurs> {
    142147                bool result;
    143                 std::set< std::string > vars;
     148                std::unordered_set< TypeInstType::TypeEnvKey > vars;
    144149                const TypeEnvironment & tenv;
    145150
    146                 Occurs( const std::string & var, const TypeEnvironment & env )
     151                Occurs( const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env )
    147152                : result( false ), vars(), tenv( env ) {
    148153                        if ( const EqvClass * clz = tenv.lookup( var ) ) {
     
    154159
    155160                void previsit( const TypeInstType * typeInst ) {
    156                         if ( vars.count( typeInst->name ) ) {
     161                        if ( vars.count( *typeInst ) ) {
    157162                                result = true;
    158                         } else if ( const EqvClass * clz = tenv.lookup( typeInst->name ) ) {
     163                        } else if ( const EqvClass * clz = tenv.lookup( *typeInst ) ) {
    159164                                if ( clz->bound ) {
    160165                                        clz->bound->accept( *visitor );
     
    165170
    166171        /// true if `var` occurs in `ty` under `env`
    167         bool occurs( const Type * ty, const std::string & var, const TypeEnvironment & env ) {
     172        bool occurs( const Type * ty, const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env ) {
    168173                Pass<Occurs> occur{ var, env };
    169174                maybe_accept( ty, occur );
     
    280285        // remove references from bound type, so that type variables can only bind to value types
    281286        ptr<Type> target = bindTo->stripReferences();
    282         auto tyvar = open.find( typeInst->name );
     287        auto tyvar = open.find( *typeInst );
    283288        assert( tyvar != open.end() );
    284289        if ( ! tyVarCompatible( tyvar->second, target ) ) return false;
    285         if ( occurs( target, typeInst->name, *this ) ) return false;
    286 
    287         auto it = internal_lookup( typeInst->name );
     290        if ( occurs( target, *typeInst, *this ) ) return false;
     291
     292        auto it = internal_lookup( *typeInst );
    288293        if ( it != env.end() ) {
    289294                if ( it->bound ) {
     
    308313        } else {
    309314                env.emplace_back(
    310                         typeInst->name, target, widen.first && widen.second, data );
     315                        *typeInst, target, widen.first && widen.second, data );
    311316        }
    312317        return true;
     
    318323                WidenMode widen, const SymbolTable & symtab
    319324) {
    320         auto c1 = internal_lookup( var1->name );
    321         auto c2 = internal_lookup( var2->name );
     325        auto c1 = internal_lookup( *var1 );
     326        auto c2 = internal_lookup( *var2 );
    322327
    323328        // exit early if variables already bound together
     
    333338        if ( c1 != env.end() ) {
    334339                if ( c1->bound ) {
    335                         if ( occurs( c1->bound, var2->name, *this ) ) return false;
     340                        if ( occurs( c1->bound, *var2, *this ) ) return false;
    336341                        type1 = c1->bound;
    337342                }
     
    340345        if ( c2 != env.end() ) {
    341346                if ( c2->bound ) {
    342                         if ( occurs( c2->bound, var1->name, *this ) ) return false;
     347                        if ( occurs( c2->bound, *var1, *this ) ) return false;
    343348                        type2 = c2->bound;
    344349                }
     
    378383        } else if ( c1 != env.end() ) {
    379384                // var2 unbound, add to env[c1]
    380                 c1->vars.emplace( var2->name );
     385                c1->vars.emplace( *var2 );
    381386                c1->allowWidening = widen1;
    382387                c1->data.isComplete |= data.isComplete;
    383388        } else if ( c2 != env.end() ) {
    384389                // var1 unbound, add to env[c2]
    385                 c2->vars.emplace( var1->name );
     390                c2->vars.emplace( *var1 );
    386391                c2->allowWidening = widen2;
    387392                c2->data.isComplete |= data.isComplete;
    388393        } else {
    389394                // neither var bound, create new class
    390                 env.emplace_back( var1->name, var2->name, widen1 && widen2, data );
     395                env.emplace_back( *var1, *var2, widen1 && widen2, data );
    391396        }
    392397
     
    452457}
    453458
    454 TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string & var ) {
     459TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const TypeInstType::TypeEnvKey & var ) {
    455460        for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) {
    456461                if ( i->vars.count( var ) ) return i;
  • src/AST/TypeEnvironment.hpp

    r42f6e07 r2b4daf2  
    5555/// recorded. More investigation is needed.
    5656struct AssertCompare {
    57         bool operator()( const DeclWithType * d1, const DeclWithType * d2 ) const {
    58                 int cmp = d1->name.compare( d2->name );
    59                 return cmp < 0 || ( cmp == 0 && d1->get_type() < d2->get_type() );
     57        bool operator()( const VariableExpr * d1, const VariableExpr * d2 ) const {
     58                int cmp = d1->var->name.compare( d2->var->name );
     59                return cmp < 0 || ( cmp == 0 && d1->result < d2->result );
    6060        }
    6161};
     
    7070
    7171/// Set of assertions pending satisfaction
    72 using AssertionSet = std::map< readonly<DeclWithType>, AssertionSetValue, AssertCompare >;
     72using AssertionSet = std::map< const VariableExpr *, AssertionSetValue, AssertCompare >;
    7373
    7474/// Set of open variables
    75 using OpenVarSet = std::unordered_map< std::string, TypeDecl::Data >;
     75using OpenVarSet = std::unordered_map< TypeInstType::TypeEnvKey, TypeDecl::Data >;
    7676
    7777/// Merges one set of open vars into another
     
    8989/// they bind to.
    9090struct EqvClass {
    91         std::set< std::string > vars;
     91        std::unordered_set< TypeInstType::TypeEnvKey > vars;
    9292        ptr<Type> bound;
    9393        bool allowWidening;
     
    101101
    102102        /// Singleton class constructor from TypeDecl
    103         EqvClass( const TypeDecl * decl )
    104         : vars{ decl->name }, bound(), allowWidening( true ), data( decl ) {}
     103        EqvClass( const TypeInstType * inst )
     104        : vars{ *inst }, bound(), allowWidening( true ), data( inst->base ) {}
    105105
    106106        /// Singleton class constructor from substitution
    107         EqvClass( const std::string & v, const Type * b )
     107        EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b )
    108108        : vars{ v }, bound( b ), allowWidening( false ), data( TypeDecl::Dtype, false ) {}
    109109
    110110        /// Single-var constructor (strips qualifiers from bound type)
    111         EqvClass( const std::string & v, const Type * b, bool w, const TypeDecl::Data & d )
     111        EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b, bool w, const TypeDecl::Data & d )
    112112        : vars{ v }, bound( b ), allowWidening( w ), data( d ) {
    113113                reset_qualifiers( bound );
     
    115115
    116116        /// Double-var constructor
    117         EqvClass( const std::string & v, const std::string & u, bool w, const TypeDecl::Data & d )
     117        EqvClass( const TypeInstType::TypeEnvKey & v, const TypeInstType::TypeEnvKey & u, bool w, const TypeDecl::Data & d )
    118118        : vars{ v, u }, bound(), allowWidening( w ), data( d ) {}
    119119
     
    131131public:
    132132        /// Finds the equivalence class containing a variable; nullptr for none such
    133         const EqvClass * lookup( const std::string & var ) const;
     133        const EqvClass * lookup( const TypeInstType::TypeEnvKey & var ) const;
    134134
    135135        /// Add a new equivalence class for each type variable
     
    207207
    208208        /// Private lookup API; returns array index of string, or env.size() for not found
    209         ClassList::iterator internal_lookup( const std::string & );
     209        ClassList::iterator internal_lookup( const TypeInstType::TypeEnvKey & );
    210210};
    211211
  • src/AST/TypeSubstitution.cpp

    r42f6e07 r2b4daf2  
    3939void TypeSubstitution::initialize( const TypeSubstitution &src, TypeSubstitution &dest ) {
    4040        dest.typeEnv.clear();
    41         dest.varEnv.clear();
    4241        dest.add( src );
    4342}
     
    4746                typeEnv[ i->first ] = i->second;
    4847        } // for
    49         for ( VarEnvType::const_iterator i = other.varEnv.begin(); i != other.varEnv.end(); ++i ) {
    50                 varEnv[ i->first ] = i->second;
    51         } // for
    5248}
    5349
    54 void TypeSubstitution::add( std::string formalType, const Type *actualType ) {
    55         typeEnv[ formalType ] = actualType;
     50void TypeSubstitution::add( const TypeInstType * formalType, const Type *actualType ) {
     51        typeEnv[ *formalType ] = actualType;
    5652}
    5753
    58 void TypeSubstitution::addVar( std::string formalExpr, const Expr *actualExpr ) {
    59         varEnv[ formalExpr ] = actualExpr;
     54void TypeSubstitution::add( const TypeInstType::TypeEnvKey & key, const Type * actualType) {
     55        typeEnv[ key ] = actualType;
    6056}
    6157
    62 void TypeSubstitution::remove( std::string formalType ) {
    63         TypeEnvType::iterator i = typeEnv.find( formalType );
     58void TypeSubstitution::remove( const TypeInstType * formalType ) {
     59        TypeEnvType::iterator i = typeEnv.find( *formalType );
    6460        if ( i != typeEnv.end() ) {
    65                 typeEnv.erase( formalType );
     61                typeEnv.erase( *formalType );
    6662        } // if
    6763}
    6864
    69 const Type *TypeSubstitution::lookup( std::string formalType ) const {
    70         TypeEnvType::const_iterator i = typeEnv.find( formalType );
     65const Type *TypeSubstitution::lookup( const TypeInstType * formalType ) const {
     66        TypeEnvType::const_iterator i = typeEnv.find( *formalType );
    7167
    7268        // break on not in substitution set
     
    7571        // attempt to transitively follow TypeInstType links.
    7672        while ( const TypeInstType *actualType = i->second.as<TypeInstType>()) {
    77                 const std::string& typeName = actualType->name;
    78 
    7973                // break cycles in the transitive follow
    80                 if ( formalType == typeName ) break;
     74                if ( *formalType == *actualType ) break;
    8175
    8276                // Look for the type this maps to, returning previous mapping if none-such
    83                 i = typeEnv.find( typeName );
     77                i = typeEnv.find( *actualType );
    8478                if ( i == typeEnv.end() ) return actualType;
    8579        }
     
    9084
    9185bool TypeSubstitution::empty() const {
    92         return typeEnv.empty() && varEnv.empty();
     86        return typeEnv.empty();
    9387}
    9488
     
    9892                TypeSubstitution * newEnv;
    9993                EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
    100                 void previsit( TypeDecl * tyDecl ) {
     94                void previsit( FunctionType * ftype ) {
    10195                        // transfer known bindings for seen type variables
    102                         if ( const Type * t = env->lookup( tyDecl->name ) ) {
    103                                 newEnv->add( tyDecl->name, t );
     96                        for (auto & formal : ftype->forall) {
     97                                if ( const Type * t = env->lookup( formal ) ) {
     98                                        newEnv->add( formal, t );
     99                                }
    104100                        }
    105101                }
     
    130126
    131127const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
    132         BoundVarsType::const_iterator bound = boundVars.find( inst->name );
     128        BoundVarsType::const_iterator bound = boundVars.find( *inst );
    133129        if ( bound != boundVars.end() ) return inst;
    134130
    135         TypeEnvType::const_iterator i = sub.typeEnv.find( inst->name );
     131        TypeEnvType::const_iterator i = sub.typeEnv.find( *inst );
    136132        if ( i == sub.typeEnv.end() ) {
    137133                return inst;
     
    141137                // TODO: investigate preventing type variables from being bound to themselves in the first place.
    142138                if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
    143                         if ( inst->name == replacement->name ) {
     139                        if ( *inst == *replacement ) {
    144140                                return inst;
    145141                        }
     
    156152}
    157153
    158 const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
    159         VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
    160         if ( i == sub.varEnv.end() ) {
    161                 return nameExpr;
    162         } else {
    163                 subCount++;
    164                 return i->second;
    165         } // if
    166 }
    167 
    168154void TypeSubstitution::Substituter::previsit( const FunctionType * ptype ) {
    169155        GuardValue( boundVars );
    170156        // bind type variables from forall-qualifiers
    171157        if ( freeOnly ) {
    172                 for ( const TypeDecl * tyvar : ptype->forall ) {
    173                                 boundVars.insert( tyvar->name );
     158                for ( auto & tyvar : ptype->forall ) {
     159                                boundVars.insert( *tyvar );
    174160                } // for
    175161        } // if
    176162}
    177163
     164/*
    178165void TypeSubstitution::Substituter::handleAggregateType( const BaseInstType * type ) {
    179166        GuardValue( boundVars );
     
    184171                        if ( ! type->params.empty() ) {
    185172                                for ( const TypeDecl * tyvar : decl->params ) {
    186                                         boundVars.insert( tyvar->name );
     173                                        boundVars.insert( *tyvar );
    187174                                } // for
    188175                        } // if
     
    198185        handleAggregateType( aggregateUseType );
    199186}
     187*/
    200188
    201189} // namespace ast
  • src/AST/TypeSubstitution.hpp

    r42f6e07 r2b4daf2  
    6969        }
    7070
    71         void add( std::string formalType, const Type *actualType );
     71        void add( const TypeInstType * formalType, const Type *actualType );
     72        void add( const TypeInstType::TypeEnvKey & key, const Type *actualType );
    7273        void add( const TypeSubstitution &other );
    73         void remove( std::string formalType );
    74         const Type *lookup( std::string formalType ) const;
     74        void remove( const TypeInstType * formalType );
     75        const Type *lookup( const TypeInstType * formalType ) const;
    7576        bool empty() const;
    76 
    77         void addVar( std::string formalExpr, const Expr *actualExpr );
    7877
    7978        template< typename FormalIterator, typename ActualIterator >
     
    101100        friend class Pass;
    102101
    103         typedef std::unordered_map< std::string, ptr<Type> > TypeEnvType;
    104         typedef std::unordered_map< std::string, ptr<Expr> > VarEnvType;
     102        typedef std::unordered_map< TypeInstType::TypeEnvKey, ptr<Type> > TypeEnvType;
    105103        TypeEnvType typeEnv;
    106         VarEnvType varEnv;
    107104
    108105  public:
     
    113110        auto   end() const -> decltype( typeEnv.  end() ) { return typeEnv.  end(); }
    114111
    115         auto beginVar()       -> decltype( varEnv.begin() ) { return varEnv.begin(); }
    116         auto   endVar()       -> decltype( varEnv.  end() ) { return varEnv.  end(); }
    117         auto beginVar() const -> decltype( varEnv.begin() ) { return varEnv.begin(); }
    118         auto   endVar() const -> decltype( varEnv.  end() ) { return varEnv.  end(); }
    119112};
    120113
     114// this is the only place where type parameters outside a function formal may be substituted.
    121115template< typename FormalIterator, typename ActualIterator >
    122116void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
     
    129123                        if ( const TypeExpr *actual = actualIt->template as<TypeExpr>() ) {
    130124                                if ( formal->name != "" ) {
    131                                         typeEnv[ formal->name ] = actual->type;
     125                                        typeEnv[ formal ] = actual->type;
    132126                                } // if
    133127                        } else {
     
    135129                        } // if
    136130                } else {
    137                         // TODO: type check the formal and actual parameters
    138                         if ( (*formalIt)->name != "" ) {
    139                                 varEnv[ (*formalIt)->name ] = *actualIt;
    140                         } // if
     131                       
    141132                } // if
    142133        } // for
    143134}
     135
     136
    144137
    145138template< typename FormalIterator, typename ActualIterator >
     
    147140        add( formalBegin, formalEnd, actualBegin );
    148141}
     142
    149143
    150144} // namespace ast
     
    164158
    165159                const Type * postvisit( const TypeInstType * aggregateUseType );
    166                 const Expr * postvisit( const NameExpr * nameExpr );
    167160
    168161                /// Records type variable bindings from forall-statements
    169162                void previsit( const FunctionType * type );
    170163                /// Records type variable bindings from forall-statements and instantiations of generic types
    171                 void handleAggregateType( const BaseInstType * type );
     164                // void handleAggregateType( const BaseInstType * type );
    172165
    173                 void previsit( const StructInstType * aggregateUseType );
    174                 void previsit( const UnionInstType * aggregateUseType );
     166                // void previsit( const StructInstType * aggregateUseType );
     167                // void previsit( const UnionInstType * aggregateUseType );
    175168
    176169                const TypeSubstitution & sub;
    177170                int subCount = 0;
    178171                bool freeOnly;
    179                 typedef std::unordered_set< std::string > BoundVarsType;
     172                typedef std::unordered_set< TypeInstType::TypeEnvKey > BoundVarsType;
    180173                BoundVarsType boundVars;
    181174
  • src/AST/module.mk

    r42f6e07 r2b4daf2  
    3333        AST/Expr.cpp \
    3434        AST/Expr.hpp \
    35         AST/ForallSubstitutionTable.cpp \
    36         AST/ForallSubstitutionTable.hpp \
    37         AST/ForallSubstitutor.hpp \
    3835        AST/FunctionSpec.hpp \
    3936        AST/Fwd.hpp \
  • src/GenPoly/GenPoly.cc

    r42f6e07 r2b4daf2  
    115115                if (!env) return type;
    116116                if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) {
    117                         auto newType = env->lookup(typeInst->name);
     117                        auto newType = env->lookup(typeInst);
    118118                        if (newType) return newType;
    119119                }
     
    172172
    173173                if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
    174                         return tyVars.find(typeInst->name) != tyVars.end() ? type : nullptr;
     174                        return tyVars.find(typeInst->typeString()) != tyVars.end() ? type : nullptr;
    175175                } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
    176176                        return isPolyType( arrayType->base, env );
     
    552552        }
    553553
    554         void addToTyVarMap( const ast::TypeDecl * tyVar, TyVarMap & tyVarMap) {
    555                 tyVarMap.insert(tyVar->name, convData(ast::TypeDecl::Data{tyVar}));
     554        void addToTyVarMap( const ast::TypeInstType * tyVar, TyVarMap & tyVarMap) {
     555                tyVarMap.insert(tyVar->typeString(), convData(ast::TypeDecl::Data{tyVar->base}));
    556556        }
    557557
  • src/InitTweak/GenInit.cc

    r42f6e07 r2b4daf2  
    122122        };
    123123
     124        struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
     125                /// hoist dimension from array types in object declaration so that it uses a single
     126                /// const variable of type size_t, so that side effecting array dimensions are only
     127                /// computed once.
     128                static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
     129
     130                void premutate( ObjectDecl * objectDecl );
     131                DeclarationWithType * postmutate( ObjectDecl * objectDecl );
     132                void premutate( FunctionDecl *functionDecl );
     133                // should not traverse into any of these declarations to find objects
     134                // that need to be constructed or destructed
     135                void premutate( AggregateDecl * ) { visit_children = false; }
     136                void premutate( NamedTypeDecl * ) { visit_children = false; }
     137                void premutate( FunctionType * ) { visit_children = false; }
     138
     139                void hoist( Type * type );
     140
     141                Type::StorageClasses storageClasses;
     142                bool inFunction = false;
     143        };
     144
    124145        void genInit( std::list< Declaration * > & translationUnit ) {
    125                 HoistArrayDimension::hoistArrayDimension( translationUnit );
     146                if (!useNewAST) {
     147                        HoistArrayDimension::hoistArrayDimension( translationUnit );
     148                }
     149                else {
     150                        HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
     151                }
    126152                fixReturnStatements( translationUnit );
    127153
     
    196222
    197223                        // need to resolve array dimensions in order to accurately determine if constexpr
    198                         if (!useNewAST) {
    199                                 ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
    200                                 // array is variable-length when the dimension is not constexpr
    201                                 arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
    202                         }
     224                        ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
     225                        // array is variable-length when the dimension is not constexpr
     226                        arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
    203227                        // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    204228                        // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
     
    218242
    219243        void HoistArrayDimension::premutate( FunctionDecl * ) {
     244                GuardValue( inFunction );
     245                inFunction = true;
     246        }
     247
     248        // precompute array dimension expression, because constructor generation may duplicate it,
     249        // which would be incorrect if it is a side-effecting computation.
     250        void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
     251                PassVisitor<HoistArrayDimension_NoResolve> hoister;
     252                mutateAll( translationUnit, hoister );
     253        }
     254
     255        void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
     256                GuardValue( storageClasses );
     257                storageClasses = objectDecl->get_storageClasses();
     258        }
     259
     260        DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
     261                hoist( objectDecl->get_type() );
     262                return objectDecl;
     263        }
     264
     265        void HoistArrayDimension_NoResolve::hoist( Type * type ) {
     266                // if in function, generate const size_t var
     267                static UniqueName dimensionName( "_array_dim" );
     268
     269                // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
     270                if ( ! inFunction ) return;
     271                if ( storageClasses.is_static ) return;
     272
     273                if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
     274                        if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
     275                        // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
     276                        // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
     277                        // still try to detect constant expressions
     278                        if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
     279
     280                        ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
     281                        arrayDimension->get_type()->set_const( true );
     282
     283                        arrayType->set_dimension( new VariableExpr( arrayDimension ) );
     284                        declsToAddBefore.push_back( arrayDimension );
     285
     286                        hoist( arrayType->get_base() );
     287                        return;
     288                }
     289        }
     290
     291        void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
    220292                GuardValue( inFunction );
    221293                inFunction = true;
  • src/ResolvExpr/AdjustExprType.cc

    r42f6e07 r2b4daf2  
    133133                const ast::Type * postvisit( const ast::TypeInstType * inst ) {
    134134                        // replace known function-type-variables with pointer-to-function
    135                         if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
     135                        if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
    136136                                if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
    137137                                        return new ast::PointerType{ inst };
  • src/ResolvExpr/CandidateFinder.cpp

    r42f6e07 r2b4daf2  
    212212                // mark type variable and specialization cost of forall clause
    213213                convCost.incVar( function->forall.size() );
    214                 for ( const ast::TypeDecl * td : function->forall ) {
    215                         convCost.decSpec( td->assertions.size() );
    216                 }
     214                convCost.decSpec( function->assertions.size() );
    217215
    218216                return convCost;
     
    223221                ast::AssertionSet & need
    224222        ) {
    225                 for ( const ast::TypeDecl * tyvar : type->forall ) {
    226                         unifiableVars[ tyvar->name ] = ast::TypeDecl::Data{ tyvar };
    227                         for ( const ast::DeclWithType * assn : tyvar->assertions ) {
    228                                 need[ assn ].isUsed = true;
    229                         }
     223                for ( auto & tyvar : type->forall ) {
     224                        unifiableVars[ *tyvar ] = ast::TypeDecl::Data{ tyvar->base };
     225                }
     226                for ( auto & assn : type->assertions ) {
     227                        need[ assn ].isUsed = true;
    230228                }
    231229        }
     
    907905                        // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
    908906                        // this means there exists ctor/assign functions with a tuple as first parameter.
    909                         funcFinder.find( untypedExpr->func, selfFinder.candidates.empty() ? ResolvMode::withAdjustment() : ResolvMode::withoutFailFast() );
     907                        ResolvMode mode = {
     908                                true, // adjust
     909                                !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
     910                                selfFinder.candidates.empty() // failfast if other options are not found
     911                        };
     912                        funcFinder.find( untypedExpr->func, mode );
    910913                        // short-circuit if no candidates
    911914                        // if ( funcFinder.candidates.empty() ) return;
     
    953956                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
    954957                                        ) {
    955                                                 if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
     958                                                if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
    956959                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    957960                                                                CandidateRef newFunc{ new Candidate{ *func } };
     
    10771080                        assert( toType );
    10781081                        toType = resolveTypeof( toType, symtab );
    1079                         toType = SymTab::validateType( castExpr->location, toType, symtab );
     1082                        // toType = SymTab::validateType( castExpr->location, toType, symtab );
    10801083                        toType = adjustExprType( toType, tenv, symtab );
    10811084
     
    11621165
    11631166                                        if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
    1164                                                 auto td = cand->env.lookup(insttype->name);
     1167                                                auto td = cand->env.lookup(*insttype);
    11651168                                                if(!td) { continue; }
    11661169                                                expr = td->bound.get();
     
    15681571                                // calculate target type
    15691572                                const ast::Type * toType = resolveTypeof( initAlt.type, symtab );
    1570                                 toType = SymTab::validateType( initExpr->location, toType, symtab );
     1573                                // toType = SymTab::validateType( initExpr->location, toType, symtab );
    15711574                                toType = adjustExprType( toType, tenv, symtab );
    15721575                                // The call to find must occur inside this loop, otherwise polymorphic return
  • src/ResolvExpr/CastCost.cc

    r42f6e07 r2b4daf2  
    202202) {
    203203        if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    204                 if ( const ast::EqvClass * eqvClass = env.lookup( typeInst->name ) ) {
     204                if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
    205205                        // check cast cost against bound type, if present
    206206                        if ( eqvClass->bound ) {
  • src/ResolvExpr/CommonType.cc

    r42f6e07 r2b4daf2  
    713713                        const ast::Type * base = oPtr->base;
    714714                        if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) {
    715                                 auto entry = open.find( var->name );
     715                                auto entry = open.find( *var );
    716716                                if ( entry != open.end() ) {
    717717                                        ast::AssertionSet need, have;
  • src/ResolvExpr/ConversionCost.cc

    r42f6e07 r2b4daf2  
    498498) {
    499499        if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    500                 if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
     500                if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) {
    501501                        if ( eqv->bound ) {
    502502                                return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
     
    675675
    676676void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
    677         if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
     677        if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) {
    678678                cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
    679679        } else if ( const ast::TypeInstType * dstAsInst =
    680680                        dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    681                 if ( typeInstType->name == dstAsInst->name ) {
     681                if ( *typeInstType == *dstAsInst ) {
    682682                        cost = Cost::zero;
    683683                }
  • src/ResolvExpr/FindOpenVars.cc

    r42f6e07 r2b4daf2  
    112112                                // mark open/closed variables
    113113                                if ( nextIsOpen ) {
    114                                         for ( const ast::TypeDecl * decl : type->forall ) {
    115                                                 open[ decl->name ] = ast::TypeDecl::Data{ decl };
    116                                                 for ( const ast::DeclWithType * assert : decl->assertions ) {
    117                                                         need[ assert ].isUsed = false;
    118                                                 }
     114                                        for ( auto & decl : type->forall ) {
     115                                                open[ *decl ] = ast::TypeDecl::Data{ decl->base };
     116                                        }
     117                                        for ( auto & assert : type->assertions ) {
     118                                                need[ assert ].isUsed = false;
    119119                                        }
    120120                                } else {
    121                                         for ( const ast::TypeDecl * decl : type->forall ) {
    122                                                 closed[ decl->name ] = ast::TypeDecl::Data{ decl };
    123                                                 for ( const ast::DeclWithType * assert : decl->assertions ) {
    124                                                         have[ assert ].isUsed = false;
    125                                                 }
     121                                        for ( auto & decl : type->forall ) {
     122                                                closed[ *decl ] = ast::TypeDecl::Data{ decl->base };   
     123                                        }
     124                                        for ( auto & assert : type->assertions ) {
     125                                                have[ assert ].isUsed = false;
    126126                                        }
    127127                                }
  • src/ResolvExpr/PolyCost.cc

    r42f6e07 r2b4daf2  
    6868
    6969        void previsit( const ast::TypeInstType * type ) {
    70                 if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {
     70                if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) {
    7171                        if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
    7272                                if ( symtab.lookupType( otherType->name ) ) {
  • src/ResolvExpr/PtrsAssignable.cc

    r42f6e07 r2b4daf2  
    134134        }
    135135        void postvisit( const ast::TypeInstType * inst ) {
    136                 if ( const ast::EqvClass * eqv = typeEnv.lookup( inst->name ) ) {
     136                if ( const ast::EqvClass * eqv = typeEnv.lookup( *inst ) ) {
    137137                        if ( eqv->bound ) {
    138138                                // T * = S * for any S depends on the type bound to T
     
    146146                const ast::TypeEnvironment & env ) {
    147147        if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    148                 if ( const ast::EqvClass * eqv = env.lookup( dstAsInst->name ) ) {
     148                if ( const ast::EqvClass * eqv = env.lookup( *dstAsInst ) ) {
    149149                        return ptrsAssignable( src, eqv->bound, env );
    150150                }
  • src/ResolvExpr/PtrsCastable.cc

    r42f6e07 r2b4daf2  
    180180                                        }
    181181                                }
    182                         } else if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
     182                        } else if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
    183183                                if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
    184184                                        return -1;
     
    283283) {
    284284        if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    285                 if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
     285                if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
    286286                        return ptrsAssignable( src, eqvClass->bound, env );
    287287                }
  • src/ResolvExpr/RenameVars.cc

    r42f6e07 r2b4daf2  
    1919#include <utility>                 // for pair
    2020
    21 #include "AST/ForallSubstitutionTable.hpp"
    2221#include "AST/Pass.hpp"
    2322#include "AST/Type.hpp"
     
    3938                int level = 0;
    4039                int resetCount = 0;
     40
     41                int next_expr_id = 1;
     42                int next_usage_id = 1;
    4143                ScopedMap< std::string, std::string > nameMap;
     44                ScopedMap< std::string, ast::TypeInstType::TypeEnvKey > idMap;
    4245        public:
    43                 ast::ForallSubstitutionTable subs;
    44 
    4546                void reset() {
    4647                        level = 0;
     
    5354                                type->name = it->second;
    5455                        }
     56                }
     57
     58                void nextUsage() {
     59                        ++next_usage_id;
    5560                }
    5661
     
    7883
    7984                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
    80                         // re-linking of base type handled by WithForallSubstitutor
    81 
    8285                        // rename
    83                         auto it = nameMap.find( type->name );
    84                         if ( it != nameMap.end() ) {
    85                                 // unconditionally mutate because map will *always* have different name,
    86                                 // if this mutates, will *always* have been mutated by ForallSubstitutor above
    87                                 ast::TypeInstType * mut = ast::mutate( type );
    88                                 mut->name = it->second;
     86                        auto it = idMap.find( type->name );
     87                        if ( it != idMap.end() ) {
     88                                // unconditionally mutate because map will *always* have different name
     89                                ast::TypeInstType * mut = ast::shallowCopy( type );
     90                                // reconcile base node since some copies might have been made
     91                                mut->base = it->second.base;
     92                                mut->formal_usage = it->second.formal_usage;
     93                                mut->expr_id = it->second.expr_id;
    8994                    type = mut;
    9095                        }
     
    9398                }
    9499
    95                 const ast::FunctionType * openLevel( const ast::FunctionType * type ) {
     100                const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
    96101                        if ( type->forall.empty() ) return type;
    97 
    98                         nameMap.beginScope();
     102                        idMap.beginScope();
    99103
    100104                        // Load new names from this forall clause and perform renaming.
    101                         auto mutType = ast::mutate( type );
    102                         assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
    103                         for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
    104                                 assertf(dynamic_cast<ast::FunctionType *>(mutType), "renaming vars in non-function type");
    105                                 std::ostringstream output;
    106                                 output << "_" << resetCount << "_" << level << "_" << td->name;
    107                                 std::string newname =  output.str();
    108                                 nameMap[ td->name ] = newname;
    109                                 ++level;
    110 
    111                                 ast::TypeDecl * mutDecl = ast::mutate( td.get() );
    112                                 assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
    113                                 mutDecl->name = newname;
    114                                 // assertion above means `td = mutDecl;` is unnecessary
    115                         }
    116                         // assertion above means `type = mutType;` is unnecessary
    117 
    118                         return type;
     105                        auto mutType = ast::shallowCopy( type );
     106                        // assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
     107                        for ( auto & td : mutType->forall ) {
     108                                auto mut = ast::shallowCopy( td.get() );
     109                                // assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
     110
     111                                if (mode == GEN_EXPR_ID) {
     112                                        mut->expr_id = next_expr_id;
     113                                        mut->formal_usage = -1;
     114                                        ++next_expr_id;
     115                                }
     116                                else if (mode == GEN_USAGE) {
     117                                        assertf(mut->expr_id, "unfilled expression id in generating candidate type");
     118                                        mut->formal_usage = next_usage_id;
     119                                }
     120                                else {
     121                                        assert(false);
     122                                }
     123                                idMap[ td->name ] = ast::TypeInstType::TypeEnvKey(*mut);
     124                               
     125                                td = mut;
     126                        }
     127
     128                        return mutType;
    119129                }
    120130
    121131                void closeLevel( const ast::FunctionType * type ) {
    122132                        if ( type->forall.empty() ) return;
    123 
    124                         nameMap.endScope();
     133                        idMap.endScope();
    125134                }
    126135        };
     
    142151        };
    143152
    144         struct RenameVars_new /*: public ast::WithForallSubstitutor*/ {
    145                 #warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor
    146                 ast::ForallSubstitutionTable & subs = renaming.subs;
     153        struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
     154                RenameMode mode;
    147155
    148156                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
    149                         return renaming.openLevel( type );
     157                        return renaming.openLevel( type, mode );
    150158                }
    151159
     
    163171
    164172                const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
     173                        if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type
    165174                        return renaming.rename( type );
    166175                }
     
    177186}
    178187
    179 const ast::Type * renameTyVars( const ast::Type * t ) {
    180         ast::Type *tc = ast::deepCopy(t);
     188const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
     189        // ast::Type *tc = ast::deepCopy(t);
    181190        ast::Pass<RenameVars_new> renamer;
    182 //      return t->accept( renamer );
    183         return tc->accept( renamer );
     191        renamer.core.mode = mode;
     192        if (mode == GEN_USAGE && reset) {
     193                renaming.nextUsage();
     194        }
     195        return t->accept( renamer );
    184196}
    185197
    186198void resetTyVarRenaming() {
    187199        renaming.reset();
     200        renaming.nextUsage();
    188201}
    189202
  • src/ResolvExpr/RenameVars.h

    r42f6e07 r2b4daf2  
    3030        /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
    3131        void renameTyVars( Type * );
    32         const ast::Type * renameTyVars( const ast::Type * );
     32
     33        enum RenameMode {
     34                GEN_USAGE, // for type in VariableExpr
     35                GEN_EXPR_ID // for type in decl
     36        };
     37        const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );
     38       
    3339
    3440        /// resets internal state of renamer to avoid overflow
    3541        void resetTyVarRenaming();
     42
     43       
    3644} // namespace ResolvExpr
    3745
  • src/ResolvExpr/ResolvMode.h

    r42f6e07 r2b4daf2  
    2323                const bool failFast;         ///< Fail on no resulting alternatives? [true]
    2424
    25         private:
    2625                constexpr ResolvMode(bool a, bool p, bool ff)
    2726                : adjust(a), prune(p), failFast(ff) {}
    2827
    29         public:
    3028                /// Default settings
    3129                constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
  • src/ResolvExpr/ResolveAssertions.cc

    r42f6e07 r2b4daf2  
    397397
    398398        /// Limit to depth of recursion of assertion satisfaction
    399         static const int recursionLimit = 4;
     399        static const int recursionLimit = 7;
    400400        /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of
    401401        static const int deferLimit = 10;
  • src/ResolvExpr/ResolveTypeof.cc

    r42f6e07 r2b4daf2  
    1515
    1616#include "ResolveTypeof.h"
     17#include "RenameVars.h"
    1718
    1819#include <cassert>               // for assert
     
    218219                        mutDecl->mangleName = Mangle::mangle(mutDecl); // do not mangle unnamed variables
    219220               
     221                mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
    220222                mutDecl->isTypeFixed = true;
    221223                return mutDecl;
  • src/ResolvExpr/Resolver.cc

    r42f6e07 r2b4daf2  
    986986                };
    987987        } // anonymous namespace
    988 
    989988        /// Check if this expression is or includes a deleted expression
    990989        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
     
    11521151                        const ast::Expr * untyped, const ast::SymbolTable & symtab
    11531152                ) {
    1154                         resetTyVarRenaming();
    11551153                        ast::TypeEnvironment env;
    11561154                        ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env );
     
    13121310        }
    13131311
    1314         ast::ptr< ast::Expr > resolveStmtExpr(
     1312        const ast::Expr * resolveStmtExpr(
    13151313                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab
    13161314        ) {
    13171315                assert( stmtExpr );
    13181316                ast::Pass< Resolver_new > resolver{ symtab };
    1319                 ast::ptr< ast::Expr > ret = stmtExpr;
    1320                 ret = ret->accept( resolver );
    1321                 strict_dynamic_cast< ast::StmtExpr * >( ret.get_and_mutate() )->computeResult();
     1317                auto ret = mutate(stmtExpr->accept(resolver));
     1318                strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
    13221319                return ret;
    13231320        }
     
    13751372                        }
    13761373
    1377                         // handle assertions. (seems deep)
     1374                        // handle assertions
    13781375
    13791376                        symtab.enterScope();
    1380                         for (auto & typeParam : mutType->forall) {
    1381                                 auto mutParam = typeParam.get_and_mutate();
    1382                                 symtab.addType(mutParam);
    1383                                 for (auto & asst : mutParam->assertions) {
    1384                                         asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
    1385                                         symtab.addId(asst);
    1386                                 }
    1387                                 typeParam = mutParam;
     1377                        mutType->forall.clear();
     1378                        mutType->assertions.clear();
     1379                        for (auto & typeParam : mutDecl->type_params) {
     1380                                symtab.addType(typeParam);
     1381                                mutType->forall.emplace_back(new ast::TypeInstType(typeParam->name, typeParam));
     1382                        }
     1383                        for (auto & asst : mutDecl->assertions) {
     1384                                asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
     1385                                symtab.addId(asst);
     1386                                mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
    13881387                        }
    13891388
     
    14071406                        mutType->returns = std::move(returnTypes);
    14081407
     1408                        auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
     1409
    14091410                        std::list<ast::ptr<ast::Stmt>> newStmts;
    14101411                        resolveWithExprs (mutDecl->withExprs, newStmts);
     
    14181419                        symtab.leaveScope();
    14191420
     1421                        mutDecl->type = renamedType;
    14201422                        mutDecl->mangleName = Mangle::mangle(mutDecl);
    14211423                        mutDecl->isTypeFixed = true;
     
    15341536        const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) {
    15351537                if ( type->dimension ) {
    1536                         #warning should use new equivalent to Validate::SizeType rather than sizeType here
    1537                         ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt };
     1538                        ast::ptr< ast::Type > sizeType = ast::sizeType;
    15381539                        ast::mutate_field(
    15391540                                type, &PtrType::dimension,
  • src/ResolvExpr/Resolver.h

    r42f6e07 r2b4daf2  
    7272        ast::ptr< ast::Init > resolveCtorInit(
    7373                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
    74         /// Resolves a statement expression
    75         ast::ptr< ast::Expr > resolveStmtExpr(
     74        /// Resolves a statement expression 
     75        const ast::Expr * resolveStmtExpr(
    7676                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab );
    7777} // namespace ResolvExpr
  • src/ResolvExpr/SatisfyAssertions.cpp

    r42f6e07 r2b4daf2  
    5757                ast::UniqueId resnSlot;          ///< Slot for any recursive assertion IDs
    5858
    59                 AssnCandidate( 
    60                         const ast::SymbolTable::IdData c, const ast::Type * at, ast::TypeEnvironment && e, 
     59                AssnCandidate(
     60                        const ast::SymbolTable::IdData c, const ast::Type * at, ast::TypeEnvironment && e,
    6161                        ast::AssertionSet && h, ast::AssertionSet && n, ast::OpenVarSet && o, ast::UniqueId rs )
    62                 : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ), 
     62                : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ),
    6363                  need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {}
    6464        };
     
    6969        /// Reference to a single deferred item
    7070        struct DeferRef {
    71                 const ast::DeclWithType * decl;
     71                const ast::VariableExpr * expr;
    7272                const ast::AssertionSetValue & info;
    7373                const AssnCandidate & match;
    7474        };
    75        
    76         /// Wrapper for the deferred items from a single assertion satisfaction. 
     75
     76        /// Wrapper for the deferred items from a single assertion satisfaction.
    7777        /// Acts like an indexed list of DeferRef
    7878        struct DeferItem {
    79                 const ast::DeclWithType * decl;
     79                const ast::VariableExpr * expr;
    8080                const ast::AssertionSetValue & info;
    8181                AssnCandidateList matches;
    8282
    83                 DeferItem( 
    84                         const ast::DeclWithType * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
    85                 : decl( d ), info( i ), matches( std::move( ms ) ) {}
     83                DeferItem(
     84                        const ast::VariableExpr * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
     85                : expr( d ), info( i ), matches( std::move( ms ) ) {}
    8686
    8787                bool empty() const { return matches.empty(); }
     
    8989                AssnCandidateList::size_type size() const { return matches.size(); }
    9090
    91                 DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; }
     91                DeferRef operator[] ( unsigned i ) const { return { expr, info, matches[i] }; }
    9292        };
    9393
     
    117117                /// Initial satisfaction state for a candidate
    118118                SatState( CandidateRef & c, const ast::SymbolTable & syms )
    119                 : cand( c ), need(), newNeed(), deferred(), inferred(), costs{ Cost::zero }, 
     119                : cand( c ), need(), newNeed(), deferred(), inferred(), costs{ Cost::zero },
    120120                  symtab( syms ) { need.swap( c->need ); }
    121                
     121
    122122                /// Update satisfaction state for next step after previous state
    123123                SatState( SatState && o, IterateFlag )
    124                 : cand( std::move( o.cand ) ), need( o.newNeed.begin(), o.newNeed.end() ), newNeed(), 
    125                   deferred(), inferred( std::move( o.inferred ) ), costs( std::move( o.costs ) ), 
     124                : cand( std::move( o.cand ) ), need( o.newNeed.begin(), o.newNeed.end() ), newNeed(),
     125                  deferred(), inferred( std::move( o.inferred ) ), costs( std::move( o.costs ) ),
    126126                  symtab( o.symtab ) { costs.emplace_back( Cost::zero ); }
    127                
     127
    128128                /// Field-wise next step constructor
    129129                SatState(
    130                         CandidateRef && c, ast::AssertionSet && nn, InferCache && i, CostVec && cs, 
     130                        CandidateRef && c, ast::AssertionSet && nn, InferCache && i, CostVec && cs,
    131131                        ast::SymbolTable && syms )
    132                 : cand( std::move( c ) ), need( nn.begin(), nn.end() ), newNeed(), deferred(), 
     132                : cand( std::move( c ) ), need( nn.begin(), nn.end() ), newNeed(), deferred(),
    133133                  inferred( std::move( i ) ), costs( std::move( cs ) ), symtab( std::move( syms ) )
    134134                  { costs.emplace_back( Cost::zero ); }
     
    138138        void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) {
    139139                for ( auto & i : have ) {
    140                         if ( i.second.isUsed ) { symtab.addId( i.first ); }
     140                        if ( i.second.isUsed ) { symtab.addId( i.first->var ); }
    141141                }
    142142        }
    143143
    144144        /// Binds a single assertion, updating satisfaction state
    145         void bindAssertion( 
    146                 const ast::DeclWithType * decl, const ast::AssertionSetValue & info, CandidateRef & cand,
     145        void bindAssertion(
     146                const ast::VariableExpr * expr, const ast::AssertionSetValue & info, CandidateRef & cand,
    147147                AssnCandidate & match, InferCache & inferred
    148148        ) {
    149149                const ast::DeclWithType * candidate = match.cdata.id;
    150                 assertf( candidate->uniqueId, 
     150                assertf( candidate->uniqueId,
    151151                        "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
    152                
     152
    153153                ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cvtCost );
    154154                varExpr->result = match.adjType;
     
    156156
    157157                // place newly-inferred assertion in proper location in cache
    158                 inferred[ info.resnSlot ][ decl->uniqueId ] = ast::ParamEntry{
    159                         candidate->uniqueId, candidate, match.adjType, decl->get_type(), varExpr };
     158                inferred[ info.resnSlot ][ expr->var->uniqueId ] = ast::ParamEntry{
     159                        candidate->uniqueId, candidate, match.adjType, expr->result, varExpr };
    160160        }
    161161
     
    169169
    170170                std::vector<ast::SymbolTable::IdData> candidates;
    171                 auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->name);
     171                auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->var->name);
    172172                if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    173173                        // prefilter special decls by argument type, if already known
    174                         ast::ptr<ast::Type> thisArgType = strict_dynamic_cast<const ast::PointerType *>(assn.first->get_type())->base
     174                        ast::ptr<ast::Type> thisArgType = assn.first->result.strict_as<ast::PointerType>()->base
    175175                                .strict_as<ast::FunctionType>()->params[0]
    176176                                .strict_as<ast::ReferenceType>()->base;
     
    184184                }
    185185                else {
    186                         candidates = sat.symtab.lookupId(assn.first->name);
     186                        candidates = sat.symtab.lookupId(assn.first->var->name);
    187187                }
    188188                for ( const ast::SymbolTable::IdData & cdata : candidates ) {
     
    200200                        ast::TypeEnvironment newEnv{ sat.cand->env };
    201201                        ast::OpenVarSet newOpen{ sat.cand->open };
    202                         ast::ptr< ast::Type > toType = assn.first->get_type();
    203                         ast::ptr< ast::Type > adjType = 
    204                                 renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ) );
     202                        ast::ptr< ast::Type > toType = assn.first->result;
     203                        ast::ptr< ast::Type > adjType =
     204                                renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ), GEN_USAGE, false );
    205205
    206206                        // only keep candidates which unify
     
    213213                                }
    214214
    215                                 matches.emplace_back( 
     215                                matches.emplace_back(
    216216                                        cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    217217                                        std::move( newOpen ), crntResnSlot );
     
    287287        };
    288288
    289         /// Replace ResnSlots with InferParams and add alternative to output list, if it meets pruning 
     289        /// Replace ResnSlots with InferParams and add alternative to output list, if it meets pruning
    290290        /// threshold.
    291         void finalizeAssertions( 
    292                 CandidateRef & cand, InferCache & inferred, PruneMap & thresholds, CostVec && costs, 
    293                 CandidateList & out 
     291        void finalizeAssertions(
     292                CandidateRef & cand, InferCache & inferred, PruneMap & thresholds, CostVec && costs,
     293                CandidateList & out
    294294        ) {
    295295                // prune if cheaper alternative for same key has already been generated
     
    308308        }
    309309
    310         /// Combo iterator that combines candidates into an output list, merging their environments. 
    311         /// Rejects an appended candidate if environments cannot be merged. See `Common/FilterCombos.h` 
     310        /// Combo iterator that combines candidates into an output list, merging their environments.
     311        /// Rejects an appended candidate if environments cannot be merged. See `Common/FilterCombos.h`
    312312        /// for description of "combo iterator".
    313313        class CandidateEnvMerger {
     
    337337                                        // compute conversion cost from satisfying decl to assertion
    338338                                        cost += computeConversionCost(
    339                                                 assn.match.adjType, assn.decl->get_type(), false, symtab, env );
     339                                                assn.match.adjType, assn.expr->result, false, symtab, env );
    340340
    341341                                        // mark vars+specialization on function-type assertions
     
    350350                                        cost.incVar( func->forall.size() );
    351351
    352                                         for ( const ast::TypeDecl * td : func->forall ) {
    353                                                 cost.decSpec( td->assertions.size() );
    354                                         }
     352                                        cost.decSpec( func->assertions.size() );
    355353                                }
    356354                        }
     
    387385
    388386        /// Limit to depth of recursion of assertion satisfaction
    389         static const int recursionLimit = 4;
     387        static const int recursionLimit = 8;
    390388        /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of
    391389        static const int deferLimit = 10;
    392390} // anonymous namespace
    393391
    394 void satisfyAssertions( 
    395         CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 
     392void satisfyAssertions(
     393        CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
    396394        std::vector<std::string> & errors
    397395) {
     
    419417                        if ( it != thresholds.end() && it->second < sat.costs ) goto nextSat;
    420418
    421                         // make initial pass at matching assertions
    422                         for ( auto & assn : sat.need ) {
    423                                 // fail early if any assertion is not satisfiable
    424                                 if ( ! satisfyAssertion( assn, sat ) ) {
     419                        // should a limit be imposed? worst case here is O(n^2) but very unlikely to happen.
     420                        for (unsigned resetCount = 0; ; ++resetCount) {
     421                                ast::AssertionList next;
     422                                resetTyVarRenaming();
     423                                // make initial pass at matching assertions
     424                                for ( auto & assn : sat.need ) {
     425                                        // fail early if any assertion is not satisfiable
     426                                        if ( ! satisfyAssertion( assn, sat ) ) {
     427                                                next.emplace_back(assn);
     428                                                // goto nextSat;
     429                                        }
     430                                }
     431                                // success
     432                                if (next.empty()) break;
     433                                // fail if nothing resolves
     434                                else if (next.size() == sat.need.size()) {
    425435                                        Indenter tabs{ 3 };
    426436                                        std::ostringstream ss;
     
    428438                                        print( ss, *sat.cand, ++tabs );
    429439                                        ss << (tabs-1) << "Could not satisfy assertion:\n";
    430                                         ast::print( ss, assn.first, tabs );
     440                                        ast::print( ss, next[0].first, tabs );
    431441
    432442                                        errors.emplace_back( ss.str() );
    433443                                        goto nextSat;
    434444                                }
     445                                sat.need = std::move(next);
    435446                        }
    436447
     
    438449                                // either add successful match or push back next state
    439450                                if ( sat.newNeed.empty() ) {
    440                                         finalizeAssertions( 
     451                                        finalizeAssertions(
    441452                                                sat.cand, sat.inferred, thresholds, std::move( sat.costs ), out );
    442453                                } else {
     
    451462                                ss << (tabs-1) << "Too many non-unique satisfying assignments for assertions:\n";
    452463                                for ( const auto & d : sat.deferred ) {
    453                                         ast::print( ss, d.decl, tabs );
     464                                        ast::print( ss, d.expr, tabs );
    454465                                }
    455466
     
    460471                                std::vector< CandidateEnvMerger::OutType > compatible = filterCombos(
    461472                                        sat.deferred, CandidateEnvMerger{ sat.cand->env, sat.cand->open, sat.symtab } );
    462                                
     473
    463474                                // fail early if no mutually-compatible assertion satisfaction
    464475                                if ( compatible.empty() ) {
     
    469480                                        ss << (tabs-1) << "No mutually-compatible satisfaction for assertions:\n";
    470481                                        for ( const auto& d : sat.deferred ) {
    471                                                 ast::print( ss, d.decl, tabs );
     482                                                ast::print( ss, d.expr, tabs );
    472483                                        }
    473484
     
    483494                                        // set up next satisfaction state
    484495                                        CandidateRef nextCand = std::make_shared<Candidate>(
    485                                                 sat.cand->expr, std::move( compat.env ), std::move( compat.open ), 
     496                                                sat.cand->expr, std::move( compat.env ), std::move( compat.open ),
    486497                                                ast::AssertionSet{} /* need moved into satisfaction state */,
    487498                                                sat.cand->cost, sat.cand->cvtCost );
     
    489500                                        ast::AssertionSet nextNewNeed{ sat.newNeed };
    490501                                        InferCache nextInferred{ sat.inferred };
    491                                        
     502
    492503                                        CostVec nextCosts{ sat.costs };
    493504                                        nextCosts.back() += compat.cost;
    494                                                                
     505
    495506                                        ast::SymbolTable nextSymtab{ sat.symtab };
    496507
     
    501512                                                nextNewNeed.insert( match.need.begin(), match.need.end() );
    502513
    503                                                 bindAssertion( r.decl, r.info, nextCand, match, nextInferred );
     514                                                bindAssertion( r.expr, r.info, nextCand, match, nextInferred );
    504515                                        }
    505516
    506517                                        // either add successful match or push back next state
    507518                                        if ( nextNewNeed.empty() ) {
    508                                                 finalizeAssertions( 
     519                                                finalizeAssertions(
    509520                                                        nextCand, nextInferred, thresholds, std::move( nextCosts ), out );
    510521                                        } else {
    511                                                 nextSats.emplace_back( 
    512                                                         std::move( nextCand ), std::move( nextNewNeed ), 
    513                                                         std::move( nextInferred ), std::move( nextCosts ), 
     522                                                nextSats.emplace_back(
     523                                                        std::move( nextCand ), std::move( nextNewNeed ),
     524                                                        std::move( nextInferred ), std::move( nextCosts ),
    514525                                                        std::move( nextSymtab ) );
    515526                                        }
     
    523534                nextSats.clear();
    524535        }
    525        
     536
    526537        // exceeded recursion limit if reaches here
    527538        if ( out.empty() ) {
  • src/ResolvExpr/Unify.cc

    r42f6e07 r2b4daf2  
    773773
    774774                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
    775                                 if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name ) ) {
     775                                if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
    776776                                        // expand ttype parameter into its actual type
    777777                                        if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
     
    811811                /// Creates a tuple type based on a list of DeclWithType
    812812                template< typename Iter >
    813                 static ast::ptr< ast::Type > tupleFromTypes( Iter crnt, Iter end ) {
     813                static const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
    814814                        std::vector< ast::ptr< ast::Type > > types;
    815815                        while ( crnt != end ) {
     
    821821                        }
    822822
    823                         return { new ast::TupleType{ std::move(types) } };
     823                        return new ast::TupleType{ std::move(types) };
    824824                }
    825825
     
    888888                }
    889889
    890                 static void markAssertionSet( ast::AssertionSet & assns, const ast::DeclWithType * assn ) {
     890                static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
    891891                        auto i = assns.find( assn );
    892892                        if ( i != assns.end() ) {
     
    900900                        const ast::FunctionType * type
    901901                ) {
    902                         for ( const auto & tyvar : type->forall ) {
    903                                 for ( const ast::DeclWithType * assert : tyvar->assertions ) {
    904                                         markAssertionSet( assn1, assert );
    905                                         markAssertionSet( assn2, assert );
    906                                 }
     902                        for ( auto & assert : type->assertions ) {
     903                                markAssertionSet( assn1, assert );
     904                                markAssertionSet( assn2, assert );
    907905                        }
    908906                }
     
    10301028
    10311029                void postvisit( const ast::TypeInstType * typeInst ) {
    1032                         assert( open.find( typeInst->name ) == open.end() );
     1030                        assert( open.find( *typeInst ) == open.end() );
    10331031                        handleRefType( typeInst, type2 );
    10341032                }
     
    10361034        private:
    10371035                /// Creates a tuple type based on a list of Type
    1038                 static ast::ptr< ast::Type > tupleFromTypes(
     1036                static const ast::Type * tupleFromTypes(
    10391037                        const std::vector< ast::ptr< ast::Type > > & tys
    10401038                ) {
     
    11711169                auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
    11721170                ast::OpenVarSet::const_iterator
    1173                         entry1 = var1 ? open.find( var1->name ) : open.end(),
    1174                         entry2 = var2 ? open.find( var2->name ) : open.end();
     1171                        entry1 = var1 ? open.find( *var1 ) : open.end(),
     1172                        entry2 = var2 ? open.find( *var2 ) : open.end();
    11751173                bool isopen1 = entry1 != open.end();
    11761174                bool isopen2 = entry2 != open.end();
  • src/SymTab/Mangler.cc

    r42f6e07 r2b4daf2  
    671671                                        int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    672672                                        mangleName += Encoding::forall;
    673                                         for ( const ast::TypeDecl * decl : ptype->forall ) {
     673                                        for ( auto & decl : ptype->forall ) {
    674674                                                switch ( decl->kind ) {
    675675                                                case ast::TypeDecl::Kind::Dtype:
     
    686686                                                } // switch
    687687                                                varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
    688                                                 for ( const ast::DeclWithType * assert : decl->assertions ) {
    689                                                         ast::Pass<Mangler_new> sub_mangler(
    690                                                                 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    691                                                         assert->accept( sub_mangler );
    692                                                         assertionNames.push_back( sub_mangler.core.get_mangleName() );
    693                                                         acount++;
    694                                                 } // for
     688                                        } // for
     689                                        for ( auto & assert : ptype->assertions ) {
     690                                                ast::Pass<Mangler_new> sub_mangler(
     691                                                        mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
     692                                                assert->var->accept( sub_mangler );
     693                                                assertionNames.push_back( sub_mangler.core.get_mangleName() );
     694                                                acount++;
    695695                                        } // for
    696696                                        mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
  • src/SymTab/Validate.cc

    r42f6e07 r2b4daf2  
    271271        };
    272272
    273         struct ArrayLength : public WithIndexer {
     273        struct InitializerLength {
    274274                /// for array types without an explicit length, compute the length and store it so that it
    275275                /// is known to the rest of the phases. For example,
     
    282282
    283283                void previsit( ObjectDecl * objDecl );
     284        };
     285
     286        struct ArrayLength : public WithIndexer {
     287                static void computeLength( std::list< Declaration * > & translationUnit );
     288
    284289                void previsit( ArrayType * arrayType );
    285290        };
     
    382387                                        FixObjectType::fix, translationUnit);
    383388                        }
    384                         Stats::Time::TimeCall("Array Length",
    385                                 ArrayLength::computeLength, translationUnit);
     389                        Stats::Time::TimeCall("Initializer Length",
     390                                InitializerLength::computeLength, translationUnit);
     391                        if (!useNewAST) {
     392                                Stats::Time::TimeCall("Array Length",
     393                                        ArrayLength::computeLength, translationUnit);
     394                        }
    386395                        Stats::Time::TimeCall("Find Special Declarations",
    387396                                Validate::findSpecialDecls, translationUnit);
     
    13321341        }
    13331342
     1343        void InitializerLength::computeLength( std::list< Declaration * > & translationUnit ) {
     1344                PassVisitor<InitializerLength> len;
     1345                acceptAll( translationUnit, len );
     1346        }
     1347
    13341348        void ArrayLength::computeLength( std::list< Declaration * > & translationUnit ) {
    13351349                PassVisitor<ArrayLength> len;
     
    13371351        }
    13381352
    1339         void ArrayLength::previsit( ObjectDecl * objDecl ) {
     1353        void InitializerLength::previsit( ObjectDecl * objDecl ) {
    13401354                if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->type ) ) {
    13411355                        if ( at->dimension ) return;
     
    13471361
    13481362        void ArrayLength::previsit( ArrayType * type ) {
    1349                 if (!useNewAST) {
    1350                         if ( type->dimension ) {
    1351                                 // need to resolve array dimensions early so that constructor code can correctly determine
    1352                                 // if a type is a VLA (and hence whether its elements need to be constructed)
    1353                                 ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
    1354 
    1355                                 // must re-evaluate whether a type is a VLA, now that more information is available
    1356                                 // (e.g. the dimension may have been an enumerator, which was unknown prior to this step)
    1357                                 type->isVarLen = ! InitTweak::isConstExpr( type->dimension );
    1358                         }
     1363                if ( type->dimension ) {
     1364                        // need to resolve array dimensions early so that constructor code can correctly determine
     1365                        // if a type is a VLA (and hence whether its elements need to be constructed)
     1366                        ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
     1367
     1368                        // must re-evaluate whether a type is a VLA, now that more information is available
     1369                        // (e.g. the dimension may have been an enumerator, which was unknown prior to this step)
     1370                        type->isVarLen = ! InitTweak::isConstExpr( type->dimension );
    13591371                }
    13601372        }
     
    14621474                }
    14631475        }
     1476
     1477        /*
    14641478
    14651479        /// Associates forward declarations of aggregates with their definitions
     
    18441858                }
    18451859        };
     1860        */
    18461861} // anonymous namespace
    18471862
     1863/*
    18481864const ast::Type * validateType(
    18491865                const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) {
     
    18541870        return type->accept( lrt )->accept( fpd );
    18551871}
     1872*/
    18561873
    18571874} // namespace SymTab
  • src/Tuples/TupleAssignment.cc

    r42f6e07 r2b4daf2  
    504504
    505505                        std::vector< ast::ptr< ast::Expr > > match() override {
    506                                 // temporary workaround for new and old ast to coexist and avoid name collision
    507                                 static UniqueName lhsNamer( "__massassign_Ln" );
    508                                 static UniqueName rhsNamer( "__massassign_Rn" );
     506                                static UniqueName lhsNamer( "__massassign_L" );
     507                                static UniqueName rhsNamer( "__massassign_R" );
    509508                                // empty tuple case falls into this matcher
    510509                                assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
     
    535534
    536535                        std::vector< ast::ptr< ast::Expr > > match() override {
    537                                 // temporary workaround for new and old ast to coexist and avoid name collision
    538                                 static UniqueName lhsNamer( "__multassign_Ln" );
    539                                 static UniqueName rhsNamer( "__multassign_Rn" );
     536                                static UniqueName lhsNamer( "__multassign_L" );
     537                                static UniqueName rhsNamer( "__multassign_R" );
    540538
    541539                                if ( lhs.size() != rhs.size() ) return {};
Note: See TracChangeset for help on using the changeset viewer.