Changes in / [28f3a19:b21c77a]


Ignore:
Location:
src
Files:
5 added
16 edited

Legend:

Unmodified
Added
Removed
  • src/Common/module.mk

    r28f3a19 rb21c77a  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Tue Sep 27 11:06:38 2016
    14 ## Update Count     : 4
     12## Last Modified By : Aaron B. Moss
     13## Last Modified On : Thu Jun 14 11:15:00 2018
     14## Update Count     : 5
    1515###############################################################################
    1616
     
    2020       Common/GC.cc \
    2121       Common/Assert.cc \
     22       Common/InternedString.cc \
    2223       Common/Heap.cc
  • src/GenPoly/Box.cc

    r28f3a19 rb21c77a  
    3838#include "Lvalue.h"                      // for generalizedLvalue
    3939#include "Parser/LinkageSpec.h"          // for C, Spec, Cforall, Intrinsic
    40 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass
    4140#include "ResolvExpr/typeops.h"          // for typesCompatible
    4241#include "ScopedSet.h"                   // for ScopedSet, ScopedSet<>::iter...
     
    592591                        // pass size/align for type variables
    593592                        for ( TyVarMap::const_iterator tyParm = exprTyVars.begin(); tyParm != exprTyVars.end(); ++tyParm ) {
    594                                 ResolvExpr::EqvClass eqvClass;
    595593                                assert( env );
    596594                                if ( tyParm->second.isComplete ) {
  • src/ResolvExpr/AdjustExprType.cc

    r28f3a19 rb21c77a  
    1919#include "SynTree/Mutator.h"      // for Mutator
    2020#include "SynTree/Type.h"         // for PointerType, TypeInstType, Type
    21 #include "TypeEnvironment.h"      // for EqvClass, TypeEnvironment
     21#include "TypeEnvironment.h"      // for ClassRef, TypeEnvironment
    2222
    2323namespace ResolvExpr {
     
    7474
    7575        Type * AdjustExprType::postmutate( TypeInstType * typeInst ) {
    76                 if ( const EqvClass* eqvClass = env.lookup( typeInst->get_name() ) ) {
    77                         if ( eqvClass->data.kind == TypeDecl::Ftype ) {
     76                if ( ClassRef eqvClass = env.lookup( typeInst->get_name() ) ) {
     77                        if ( eqvClass.get_bound().data.kind == TypeDecl::Ftype ) {
    7878                                return new PointerType{ Type::Qualifiers(), typeInst };
    7979                        }
  • src/ResolvExpr/AlternativeFinder.cc

    r28f3a19 rb21c77a  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 23:52:08 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 17 11:19:39 2018
    13 // Update Count     : 33
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 11 16:40:00 2018
     13// Update Count     : 34
    1414//
    1515
     
    1919#include <iostream>                // for operator<<, cerr, ostream, endl
    2020#include <iterator>                // for back_insert_iterator, back_inserter
     21#include <limits>                  // for numeric_limits<int>::max()
    2122#include <list>                    // for _List_iterator, list, _List_const_...
    2223#include <map>                     // for _Rb_tree_iterator, map, _Rb_tree_c...
    2324#include <memory>                  // for allocator_traits<>::value_type
     25#include <tuple>                   // for tuple
    2426#include <utility>                 // for pair
    2527#include <vector>                  // for vector
     
    244246        }
    245247
    246         void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
     248        void AlternativeFinder::find( Expression *expr, ResolvMode mode ) {
    247249                PassVisitor<Finder> finder( *this );
    248250                expr->accept( finder );
    249                 if ( failFast && alternatives.empty() ) {
     251                if ( mode.failFast && alternatives.empty() ) {
    250252                        PRINT(
    251253                                std::cerr << "No reasonable alternatives for expression " << expr << std::endl;
     
    253255                        SemanticError( expr, "No reasonable alternatives for expression " );
    254256                }
    255                 if ( prune ) {
     257                if ( mode.prune ) {
    256258                        auto oldsize = alternatives.size();
    257259                        PRINT(
     
    261263                        AltList pruned;
    262264                        pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) );
    263                         if ( failFast && pruned.empty() ) {
     265                        if ( mode.failFast && pruned.empty() ) {
    264266                                std::ostringstream stream;
    265267                                AltList winners;
     
    280282                }
    281283                // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
    282                 for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
    283                         if ( adjust ) {
    284                                 adjustExprType( i->expr->get_result(), i->env, indexer );
     284                if ( mode.adjust ) {
     285                        for ( Alternative& i : alternatives ) {
     286                                adjustExprType( i.expr->result, i.env, indexer );
    285287                        }
    286288                }
     
    294296
    295297        void AlternativeFinder::findWithAdjustment( Expression *expr ) {
    296                 find( expr, true );
     298                find( expr, ResolvMode::withAdjustment() );
    297299        }
    298300
    299301        void AlternativeFinder::findWithoutPrune( Expression * expr ) {
    300                 find( expr, true, false );
     302                find( expr, ResolvMode::withoutPrune() );
    301303        }
    302304
    303305        void AlternativeFinder::maybeFind( Expression * expr ) {
    304                 find( expr, true, true, false );
     306                find( expr, ResolvMode::withoutFailFast() );
    305307        }
    306308
     
    452454                }
    453455
     456                #if 0 // cost of assertions accounted for in function creation
    454457                for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
    455458                        convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
    456459                }
     460                #endif
    457461
    458462                return convCost;
     
    580584        }
    581585
     586        namespace {
     587                /// Information required to defer resolution of an expression
     588                struct AssertionPack {
     589                        SymTab::Indexer::IdData cdata;  ///< Satisfying declaration
     590                        Type* adjType;                  ///< Satisfying type
     591                        TypeEnvironment env;            ///< Post-unification environment
     592                        AssertionSet have;              ///< Post-unification have-set
     593                        AssertionSet need;              ///< Post-unification need-set
     594                        OpenVarSet openVars;            ///< Post-unification open-var set
     595
     596                        AssertionPack( const SymTab::Indexer::IdData& cdata, Type* adjType,
     597                                        TypeEnvironment&& env, AssertionSet&& have, AssertionSet&& need,
     598                                        OpenVarSet&& openVars )
     599                                : cdata(cdata), adjType(adjType), env(std::move(env)), have(std::move(have)),
     600                                  need(std::move(need)), openVars(std::move(openVars)) {}
     601                };
     602
     603                /// List of deferred assertion resolutions for the same type
     604                using DeferList = std::vector<AssertionPack>;
     605
     606                /// Intermediate state for assertion resolution
     607                struct AssertionResnState {
     608                        using DeferItem = std::tuple<DeclarationWithType*, AssertionSetValue, DeferList>;
     609
     610                        const Alternative& alt;           ///< Alternative being built from
     611                        AssertionSet newNeed;             ///< New assertions found from current assertions
     612                        OpenVarSet openVars;              ///< Open variables in current context
     613                        std::vector<DeferItem> deferred;  ///< Possible deferred assertion resolutions
     614                        const SymTab::Indexer& indexer;   ///< Name lookup
     615
     616                        AssertionResnState(const Alternative& alt, const OpenVarSet& openVars,
     617                                const SymTab::Indexer& indexer )
     618                                : alt{alt}, have{}, newNeed{}, openVars{openVars}, indexer{indexer} {}
     619                };
     620
     621                /// Binds a single assertion from a compatible AssertionPack, updating resolution state
     622                /// as appropriate.
     623                void bindAssertion( DeclarationWithType* curDecl, AssertionSetValue& assnInfo,
     624                                AssertionResnState& resn, AssertionPack&& match ) {
     625                        DeclarationWithType* candidate = match.cdata.id;
     626                       
     627                        addToIndexer( match.have, resn.indexer );
     628                        resn.newNeed.insert( match.need.begin(), match.need.end() );
     629                        resn.openVars = std::move(match.openVars);
     630                        resn.alt.env = std::move(match.env);
     631
     632                        assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
     633                        for ( auto& a : match.need ) {
     634                                if ( a.second.idChain.empty() ) {
     635                                        a.second.idChain = assnInfo.idChain;
     636                                        a.second.idChain.push_back( curDecl->get_uniqueId() );
     637                                }
     638                        }
     639
     640                        Expression* varExpr = match.cdata.combine( resn.alt.cvtCost );
     641                        varExpr->result = match.adjType;
     642
     643                        // follow the current assertion's ID chain to find the correct set of inferred
     644                        // parameters to add the candidate o (i.e. the set of inferred parameters belonging
     645                        // to the entity which requested the assertion parameter)
     646                        InferredParams* inferParams = &resn.alt.expr->inferParams;
     647                        for ( UniqueId id : assnInfo.idChain ) {
     648                                inferParams = (*inferParams)[ id ].inferParams.get();
     649                        }
     650
     651                        (*inferParams)[ curDecl->get_uniqueId() ] = ParamEntry{
     652                                candidate->get_uniqueId(), match.adjType, curDecl->get_type(), varExpr };
     653                }
     654
     655                /// Resolves a single assertion, returning false if no satisfying assertion, binding it
     656                /// if there is exactly one satisfying assertion, or adding to the defer-list if there
     657                /// is more than one
     658                bool resolveAssertion( DeclarationWithType* curDecl, AssertionSetValue& assnInfo,
     659                                AssertionResnState& resn ) {
     660                        // skip unused assertions
     661                        if ( ! assnInfo.isUsed ) return true;
     662
     663                        // lookup candidates for this assertion
     664                        std::list< SymTab::Indexer::IdData > candidates;
     665                        decls.lookupId( curDecl->name, candidates );
     666
     667                        // find the ones that unify with the desired type
     668                        DeferList matches;
     669                        for ( const auto& cdata : candidates ) {
     670                                DeclarationWithType* candidate = cdata.id;
     671
     672                                // build independent unification context for candidate
     673                                AssertionSet have, newNeed;
     674                                TypeEnvironment newEnv{ resn.alt.env };
     675                                OpenVarSet newOpenVars{ resn.openVars };
     676                                Type* adjType = candidate->get_type()->clone();
     677                                adjustExprType( adjType, newEnv, resn.indexer );
     678                                renameTyVars( adjType );
     679
     680                                if ( unify( curDecl->get_type(), adjType, newEnv,
     681                                                newNeed, have, newOpenVars, resn.indexer ) ) {
     682                                        matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have),
     683                                                std::move(newNeed), std::move(newOpenVars) );
     684                                }
     685                        }
     686
     687                        // Break if no suitable assertion
     688                        if ( matches.empty() ) return false;
     689
     690                        // Defer if too many suitable assertions
     691                        if ( matches.size() > 1 ) {
     692                                resn.deferred.emplace_back( curDecl, assnInfo, std::move(matches) );
     693                                return true;
     694                        }
     695
     696                        // otherwise bind current match in ongoing scope
     697                        bindAssertion( curDecl, assnInfo, resn, std::move(matches.front()) );
     698
     699                        return true;
     700                }
     701        }
     702
    582703        template< typename OutputIterator >
    583704        void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
     
    594715                // )
    595716                addToIndexer( have, decls );
     717
     718                AssertionResnState resn{ newAlt, openVars, indexer };
     719
     720                // resolve assertions in breadth-first-order up to a limited number of levels deep
     721                int level;
     722                for ( level = 0; level < recursionLimit; ++level ) {
     723                        // make initial pass at matching assertions
     724                        for ( auto& assn : need ) {
     725                                if ( ! resolveAssertion( assn.first, assn.second, resn ) ) {
     726                                        // fail early if any assertion fails to resolve
     727                                        return;
     728                                }
     729                        }
     730
     731                        // resolve deferred assertions by mutual compatibility and min-cost
     732                        if ( ! resn.deferred.empty() ) {
     733                                // TODO
     734                                assert(false && "TODO: deferred assertions unimplemented");
     735
     736                                // reset for next round
     737                                resn.deferred.clear();
     738                        }
     739
     740                        // quit resolving assertions if done
     741                        if ( resn.newNeed.empty() ) break;
     742
     743                        // otherwise start on next group of recursive assertions
     744                        need.swap( resn.newNeed );
     745                        resn.newNeed.clear();
     746                }
     747                if ( level >= recursionLimit ) {
     748                        SemanticError( newAlt.expr->location, "Too many recursive assertions" );
     749                }
     750               
     751                // add completed assertion to output
     752                *out++ = newAlt;
     753
     754#if 0           
    596755                AssertionSet newNeed;
    597756                PRINT(
     
    607766//          *out++ = newAlt;
    608767//          )
     768#endif
    609769        }
    610770
     
    640800
    641801                ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
    642                                 const OpenVarSet& openVars)
    643                         : parent(0), expr(nullptr), cost(Cost::zero), env(env), need(need), have(have),
     802                                const OpenVarSet& openVars, Cost initCost = Cost::zero)
     803                        : parent(0), expr(nullptr), cost(initCost), env(env), need(need), have(have),
    644804                          openVars(openVars), nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
    645805
     
    9331093        }
    9341094
     1095        namespace {
     1096
     1097                struct CountSpecs : public WithVisitorRef<CountSpecs>, WithShortCircuiting {
     1098
     1099                        void postvisit(PointerType*) {
     1100                                // mark specialization of base type
     1101                                if ( count >= 0 ) ++count;
     1102                        }
     1103
     1104                        void postvisit(ArrayType*) {
     1105                                // mark specialization of base type
     1106                                if ( count >= 0 ) ++count;
     1107                        }
     1108
     1109                        void postvisit(ReferenceType*) {
     1110                                // mark specialization of base type -- xxx maybe not?
     1111                                if ( count >= 0 ) ++count;
     1112                        }
     1113
     1114                private:
     1115                        // takes minimum non-negative count over parameter/return list
     1116                        void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {
     1117                                for ( DeclarationWithType* dwt : dwts ) {
     1118                                        count = -1;
     1119                                        maybeAccept( dwt->get_type(), *visitor );
     1120                                        if ( count != -1 && count < mincount ) mincount = count;
     1121                                }
     1122                        }
     1123
     1124                public:
     1125                        void previsit(FunctionType*) {
     1126                                // override default child visiting behaviour
     1127                                visit_children = false;
     1128                        }
     1129
     1130                        void postvisit(FunctionType* fty) {
     1131                                // take minimal set value of count over ->returnVals and ->parameters
     1132                                int mincount = std::numeric_limits<int>::max();
     1133                                takeminover( mincount, fty->parameters );
     1134                                takeminover( mincount, fty->returnVals );
     1135                                // add another level to mincount if set
     1136                                count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
     1137                        }
     1138
     1139                private:
     1140                        // returns minimum non-negative count + 1 over type parameters (-1 if none such)
     1141                        int minover( std::list<Expression*>& parms ) {
     1142                                int mincount = std::numeric_limits<int>::max();
     1143                                for ( Expression* parm : parms ) {
     1144                                        count = -1;
     1145                                        maybeAccept( parm->get_result(), *visitor );
     1146                                        if ( count != -1 && count < mincount ) mincount = count;
     1147                                }
     1148                                return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
     1149                        }
     1150                       
     1151                public:
     1152                        void previsit(StructInstType*) {
     1153                                // override default child behaviour
     1154                                visit_children = false;
     1155                        }
     1156
     1157                        void postvisit(StructInstType* sity) {
     1158                                // look for polymorphic parameters
     1159                                count = minover( sity->parameters );
     1160                        }
     1161
     1162                        void previsit(UnionInstType*) {
     1163                                // override default child behaviour
     1164                                visit_children = false;
     1165                        }
     1166
     1167                        void postvisit(UnionInstType* uity) {
     1168                                // look for polymorphic parameters
     1169                                count = minover( uity->parameters );
     1170                        }
     1171
     1172                        void postvisit(TypeInstType*) {
     1173                                // note polymorphic type (which may be specialized)
     1174                                // xxx - maybe account for open/closed type variables
     1175                                count = 0;
     1176                        }
     1177
     1178                        void previsit(TupleType*) {
     1179                                // override default child behaviour
     1180                                visit_children = false;
     1181                        }
     1182
     1183                        void postvisit(TupleType* tty) {
     1184                                // take minimum non-negative count
     1185                                int mincount = std::numeric_limits<int>::max();
     1186                                for ( Type* ty : tty->types ) {
     1187                                        count = -1;
     1188                                        maybeAccept( ty, *visitor );
     1189                                        if ( count != -1 && count < mincount ) mincount = count;
     1190                                }
     1191                                // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
     1192                                count = mincount < std::numeric_limits<int>::max() ? mincount + 1: -1;
     1193                        }
     1194
     1195                        int get_count() const { return count >= 0 ? count : 0; }
     1196                private:
     1197                        int count = -1;
     1198                };
     1199
     1200                /// Counts the specializations in the types in a function parameter or return list
     1201                int countSpecs( std::list<DeclarationWithType*>& dwts ) {
     1202                        int k = 0;
     1203                        for ( DeclarationWithType* dwt : dwts ) {
     1204                                PassVisitor<CountSpecs> counter;
     1205                                maybeAccept( dwt->get_type(), *counter.pass.visitor );
     1206                                k += counter.pass.get_count();
     1207                        }
     1208                        return k;
     1209                }
     1210
     1211                /// Calculates the inherent costs in a function declaration; varCost for the number of
     1212                /// type variables and specCost for type assertions, as well as PolyType specializations
     1213                /// in the parameter and return lists.
     1214                Cost declCost( FunctionType* funcType ) {
     1215                        Cost k = Cost::zero;
     1216
     1217                        // add cost of type variables
     1218                        k.incVar( funcType->forall.size() );
     1219
     1220                        // subtract cost of type assertions
     1221                        for ( TypeDecl* td : funcType->forall ) {
     1222                                k.decSpec( td->assertions.size() );
     1223                        }
     1224
     1225                        // count specialized polymorphic types in parameter/return lists
     1226                        k.decSpec( countSpecs( funcType->parameters ) );
     1227                        k.decSpec( countSpecs( funcType->returnVals ) );
     1228
     1229                        return k;
     1230                }
     1231        }
     1232
    9351233        template<typename OutputIterator>
    9361234        void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func,
     
    9771275                }
    9781276
     1277                // calculate declaration cost of function (+vars-spec)
     1278                Cost funcCost = declCost( funcType );
     1279
    9791280                // iteratively build matches, one parameter at a time
    9801281                std::vector<ArgPack> results;
    981                 results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } );
     1282                results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars, funcCost } );
    9821283                std::size_t genStart = 0;
    9831284
     
    11201421                                        }
    11211422                                } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
    1122                                         if ( const EqvClass *eqvClass = func->env.lookup( typeInst->name ) ) {
    1123                                                 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass->type ) ) {
     1423                                        if ( ClassRef eqvClass = func->env.lookup( typeInst->name ) ) {
     1424                                                if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.get_bound().type ) ) {
    11241425                                                        Alternative newFunc( *func );
    11251426                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
  • src/ResolvExpr/AlternativeFinder.h

    r28f3a19 rb21c77a  
    2222#include "Alternative.h"                 // for AltList, Alternative
    2323#include "ExplodedActual.h"              // for ExplodedActual
     24#include "ResolvMode.h"                  // for ResolvMode
    2425#include "ResolvExpr/Cost.h"             // for Cost, Cost::infinity
    2526#include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
     
    6869                }
    6970
    70                 void find( Expression *expr, bool adjust = false, bool prune = true, bool failFast = true );
     71                void find( Expression *expr, ResolvMode mode = ResolvMode{} );
    7172                /// Calls find with the adjust flag set; adjustment turns array and function types into equivalent pointer types
    7273                void findWithAdjustment( Expression *expr );
  • src/ResolvExpr/CastCost.cc

    r28f3a19 rb21c77a  
    1818#include "ConversionCost.h"              // for ConversionCost
    1919#include "Cost.h"                        // for Cost, Cost::infinity
    20 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment, EqvClass
     20#include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment, ClassRef
    2121#include "SymTab/Indexer.h"              // for Indexer
    2222#include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
     
    4343        Cost castCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    4444                if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
    45                         if ( const EqvClass* eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    46                                 if ( eqvClass->type ) {
    47                                         return castCost( src, eqvClass->type, indexer, env );
     45                        if ( ClassRef eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
     46                                if ( Type* boundTy = eqvClass.get_bound().type ) {
     47                                        return castCost( src, boundTy, indexer, env );
    4848                                } else {
    4949                                        return Cost::infinity;
  • src/ResolvExpr/ConversionCost.cc

    r28f3a19 rb21c77a  
    2222#include "Common/GC.h"                   // for new_static_root
    2323#include "ResolvExpr/Cost.h"             // for Cost
    24 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     24#include "ResolvExpr/TypeEnvironment.h"  // for ClassRef, TypeEnvironment
    2525#include "SymTab/Indexer.h"              // for Indexer
    2626#include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
     
    2929
    3030namespace ResolvExpr {
    31         const Cost Cost::zero =      Cost(  0,  0,  0,  0 );
    32         const Cost Cost::infinity =  Cost( -1, -1, -1, -1 );
    33         const Cost Cost::unsafe =    Cost(  1,  0,  0,  0 );
    34         const Cost Cost::poly =      Cost(  0,  1,  0,  0 );
    35         const Cost Cost::safe =      Cost(  0,  0,  1,  0 );
    36         const Cost Cost::reference = Cost(  0,  0,  0,  1 );
     31        const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0 };
     32        const Cost Cost::infinity =  Cost{ -1, -1, -1,  1, -1, -1 };
     33        const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0 };
     34        const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0 };
     35        const Cost Cost::var =       Cost{  0,  0,  1,  0,  0,  0 };
     36        const Cost Cost::spec =      Cost{  0,  0,  0, -1,  0,  0 };
     37        const Cost Cost::safe =      Cost{  0,  0,  0,  0,  1,  0 };
     38        const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  1 };
    3739
    3840#if 0
     
    4446                if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
    4547                        PRINT( std::cerr << "type inst " << destAsTypeInst->name; )
    46                         if ( const EqvClass* eqvClass = env.lookup( destAsTypeInst->name ) ) {
    47                                 if ( eqvClass->type ) {
    48                                         return conversionCost( src, eqvClass->type, indexer, env );
     48                        if ( ClassRef eqvClass = env.lookup( destAsTypeInst->name ) ) {
     49                                if ( Type* boundTy = eqvClass.get_bound().type ) {
     50                                        return conversionCost( src, boundTy, indexer, env );
    4951                                } else {
    5052                                        return Cost::infinity;
     
    368370
    369371        void ConversionCost::postvisit( TypeInstType *inst ) {
    370                 if ( const EqvClass *eqvClass = env.lookup( inst->name ) ) {
    371                         cost = costFunc( eqvClass->type, dest, indexer, env );
     372                if ( ClassRef eqvClass = env.lookup( inst->name ) ) {
     373                        cost = costFunc( eqvClass.get_bound().type, dest, indexer, env );
    372374                } else if ( TypeInstType *destAsInst = dynamic_cast< TypeInstType* >( dest ) ) {
    373375                        if ( inst->name == destAsInst->name ) {
  • src/ResolvExpr/Cost.h

    r28f3a19 rb21c77a  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 09:39:50 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:35:55 2017
    13 // Update Count     : 5
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 11 16:04:00 2018
     13// Update Count     : 6
    1414//
    1515
     
    2121        class Cost {
    2222          private:
    23                 Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost );
     23                Cost( int unsafeCost, int polyCost, int varCost, int specCost, int safeCost, int referenceCost );
    2424
    2525          public:
    2626                Cost & incUnsafe( int inc = 1 );
    2727                Cost & incPoly( int inc = 1 );
     28                Cost & incVar( int inc = 1 );
     29                Cost & decSpec( int dec = 1 );
    2830                Cost & incSafe( int inc = 1 );
    2931                Cost & incReference( int inc = 1 );
     
    3133                int get_unsafeCost() const { return unsafeCost; }
    3234                int get_polyCost() const { return polyCost; }
     35                int get_varCost() const { return varCost; }
     36                int get_specCost() const { return specCost; }
    3337                int get_safeCost() const { return safeCost; }
    3438                int get_referenceCost() const { return referenceCost; }
     
    4751                static const Cost unsafe;
    4852                static const Cost poly;
     53                static const Cost var;
     54                static const Cost spec;
    4955                static const Cost safe;
    5056                static const Cost reference;
    5157          private:
    52                 int compare( const Cost &other ) const;
    5358
    54                 int unsafeCost;
    55                 int polyCost;
    56                 int safeCost;
    57                 int referenceCost;
     59                int unsafeCost;     ///< Unsafe (narrowing) conversions
     60                int polyCost;       ///< Count of parameters and return values bound to some poly type
     61                int varCost;        ///< Count of polymorphic type variables
     62                int specCost;       ///< Polymorphic type specializations (type assertions), negative cost
     63                int safeCost;       ///< Safe (widening) conversions
     64                int referenceCost;  ///< reference conversions
    5865        };
    5966
    60         inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost ) : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), referenceCost( referenceCost ) {}
     67        inline Cost::Cost(
     68                int unsafeCost, int polyCost, int varCost, int specCost, int safeCost, int referenceCost ) : unsafeCost( unsafeCost ), polyCost( polyCost ), varCost( varCost ), specCost( specCost ),
     69                  safeCost( safeCost ), referenceCost( referenceCost ) {}
    6170
    6271        inline Cost & Cost::incUnsafe( int inc ) {
     
    6978                if ( *this == infinity ) return *this;
    7079                polyCost += inc;
     80                return *this;
     81        }
     82
     83        inline Cost & Cost::incVar( int inc ) {
     84                if ( *this == infinity ) return *this;
     85                varCost += inc;
     86                return *this;
     87        }
     88
     89        inline Cost& Cost::decSpec( int dec ) {
     90                if ( *this == infinity ) return *this;
     91                specCost -= dec;
    7192                return *this;
    7293        }
     
    86107        inline Cost Cost::operator+( const Cost &other ) const {
    87108                if ( *this == infinity || other == infinity ) return infinity;
    88                 return Cost( unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost, referenceCost + other.referenceCost );
     109                return Cost(
     110                        unsafeCost + other.unsafeCost, polyCost + other.polyCost,
     111                        varCost + other.varCost, specCost + other.specCost,
     112                        safeCost + other.safeCost, referenceCost + other.referenceCost );
    89113        }
    90114
    91115        inline Cost Cost::operator-( const Cost &other ) const {
    92116                if ( *this == infinity || other == infinity ) return infinity;
    93                 return Cost( unsafeCost - other.unsafeCost, polyCost - other.polyCost, safeCost - other.safeCost, referenceCost - other.referenceCost );
     117                return Cost(
     118                        unsafeCost - other.unsafeCost, polyCost - other.polyCost,
     119                        varCost + other.varCost, specCost + other.specCost,
     120                        safeCost - other.safeCost, referenceCost - other.referenceCost );
    94121        }
    95122
     
    102129                unsafeCost += other.unsafeCost;
    103130                polyCost += other.polyCost;
     131                varCost += other.varCost;
     132                specCost += other.specCost;
    104133                safeCost += other.safeCost;
    105134                referenceCost += other.referenceCost;
     
    119148                } else if ( polyCost < other.polyCost ) {
    120149                        return true;
     150                } else if ( varCost > other.varCost ) {
     151                        return false;
     152                } else if ( varCost < other.varCost ) {
     153                        return true;
     154                } else if ( specCost > other.specCost ) {
     155                        return false;
     156                } else if ( specCost < other.specCost ) {
     157                        return true;
    121158                } else if ( safeCost > other.safeCost ) {
    122159                        return false;
     
    135172                return unsafeCost == other.unsafeCost
    136173                        && polyCost == other.polyCost
     174                        && varCost == other.varCost
     175                        && specCost == other.specCost
    137176                        && safeCost == other.safeCost
    138177                        && referenceCost == other.referenceCost;
     
    144183
    145184        inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
    146                 os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " << cost.safeCost << ", " << cost.referenceCost << " )";
    147                 return os;
     185                return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", "
     186                          << cost.varCost << ", " << cost.specCost << ", "
     187                          << cost.safeCost << ", " << cost.referenceCost << " )";
    148188        }
    149189} // namespace ResolvExpr
  • src/ResolvExpr/Occurs.cc

    r28f3a19 rb21c77a  
    1414//
    1515
    16 #include <set>                // for set, _Rb_tree_const_iterator
    1716#include <string>             // for string
     17#include <unordered_set>      // for unordered_set
    1818
    1919#include "Common/PassVisitor.h"
    2020#include "SynTree/Type.h"     // for TypeInstType, Type
    21 #include "TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     21#include "TypeEnvironment.h"  // for ClassRef, TypeEnvironment
    2222
    2323namespace ResolvExpr {
     
    2727
    2828                bool result;
    29                 std::set< std::string > eqvVars;
     29                using VarSet = std::unordered_set< std::string >;
     30                VarSet eqvVars;
    3031                const TypeEnvironment &tenv;
    3132        };
     
    3839
    3940        Occurs::Occurs( std::string varName, const TypeEnvironment & env ) : result( false ), tenv( env ) {
    40                 if ( const EqvClass *eqvClass = tenv.lookup( varName ) ) {
    41                         eqvVars = eqvClass->vars;
     41                if ( ClassRef eqvClass = tenv.lookup( varName ) ) {
     42                        eqvVars = eqvClass.get_vars<VarSet>();
    4243                } else {
    4344                        eqvVars.insert( varName );
     
    5152                if ( eqvVars.find( typeInst->get_name() ) != eqvVars.end() ) {
    5253                        result = true;
    53                 } else if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {
    54                         if ( eqvClass->type ) {
     54                } else if ( ClassRef eqvClass = tenv.lookup( typeInst->get_name() ) ) {
     55                        if ( Type* boundTy = eqvClass.get_bound().type ) {
    5556///       std::cerr << typeInst->get_name() << " is bound to";
    56 ///       eqvClass.type->print( std::cerr );
     57///       boundTy->print( std::cerr );
    5758///       std::cerr << std::endl;
    58                                 eqvClass->type->accept( *visitor );
     59                                boundTy->accept( *visitor );
    5960                        } // if
    6061                } // if
  • src/ResolvExpr/PolyCost.cc

    r28f3a19 rb21c77a  
    1717#include "SymTab/Indexer.h"   // for Indexer
    1818#include "SynTree/Type.h"     // for TypeInstType, Type
    19 #include "TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     19#include "TypeEnvironment.h"  // for ClassRef, TypeEnvironment
    2020
    2121namespace ResolvExpr {
     
    3939
    4040        void PolyCost::previsit(TypeInstType * typeInst) {
    41                 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) {
    42                         if ( eqvClass->type ) {
    43                                 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) {
     41                if ( ClassRef eqvClass = tenv.lookup( typeInst->name ) ) {
     42                        if ( Type* boundTy = eqvClass.get_bound().type ) {
     43                                if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( boundTy ) ) {
    4444                                        if ( indexer.lookupType( otherTypeInst->name ) ) {
    4545                                                // bound to opaque type
  • src/ResolvExpr/PtrsAssignable.cc

    r28f3a19 rb21c77a  
    1515
    1616#include "Common/PassVisitor.h"
    17 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     17#include "ResolvExpr/TypeEnvironment.h"  // for ClassRef, TypeEnvironment
    1818#include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
    1919#include "SynTree/Visitor.h"             // for Visitor
     
    5151                // std::cerr << "assignable: " << src << " | " << dest << std::endl;
    5252                if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
    53                         if ( const EqvClass *eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    54                                 return ptrsAssignable( src, eqvClass->type, env );
     53                        if ( ClassRef eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
     54                                return ptrsAssignable( src, eqvClass.get_bound().type, env );
    5555                        } // if
    5656                } // if
     
    9494        void PtrsAssignable::postvisit(  __attribute__((unused)) TraitInstType *inst ) {}
    9595        void PtrsAssignable::postvisit( TypeInstType *inst ) {
    96                 if ( const EqvClass *eqvClass = env.lookup( inst->get_name() ) ) {
    97                         if ( eqvClass->type ) {
     96                if ( ClassRef eqvClass = env.lookup( inst->get_name() ) ) {
     97                        if ( Type* boundTy = eqvClass.get_bound().type ) {
    9898                                // T * = S * for any S depends on the type bound to T
    99                                 result = ptrsAssignable( eqvClass->type, dest, env );
     99                                result = ptrsAssignable( boundTy, dest, env );
    100100                        }
    101101                } // if
  • src/ResolvExpr/PtrsCastable.cc

    r28f3a19 rb21c77a  
    1515
    1616#include "Common/PassVisitor.h"
    17 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     17#include "ResolvExpr/TypeEnvironment.h"  // for ClassRef, TypeEnvironment
    1818#include "SymTab/Indexer.h"              // for Indexer
    1919#include "SynTree/Declaration.h"         // for TypeDecl, TypeDecl::Kind::Ftype
     
    6363                                                } // if
    6464                                        } //if
    65                                 } else if ( const EqvClass *eqvClass = env.lookup( typeInst->get_name() ) ) {
    66                                         if ( eqvClass->data.kind == TypeDecl::Ftype ) {
     65                                } else if ( ClassRef eqvClass = env.lookup( typeInst->get_name() ) ) {
     66                                        if ( eqvClass.get_bound().data.kind == TypeDecl::Ftype ) {
    6767                                                return -1;
    6868                                        } // if
     
    7878        int ptrsCastable( Type *src, Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    7979                if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
    80                         if ( const EqvClass *eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
     80                        if ( ClassRef eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    8181                                // xxx - should this be ptrsCastable?
    82                                 return ptrsAssignable( src, eqvClass->type, env );
     82                                return ptrsAssignable( src, eqvClass.get_bound().type, env );
    8383                        } // if
    8484                } // if
  • src/ResolvExpr/Resolver.cc

    r28f3a19 rb21c77a  
    3333#include "ResolveTypeof.h"               // for resolveTypeof
    3434#include "Resolver.h"
     35#include "ResolvMode.h"                  // for ResolvMode
    3536#include "SymTab/Autogen.h"              // for SizeType
    3637#include "SymTab/Indexer.h"              // for Indexer
     
    5051namespace ResolvExpr {
    5152        struct Resolver final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver>, public WithShortCircuiting, public WithStmtsToAdd {
     53       
     54        friend void resolve( std::list<Declaration*> );
     55
    5256                Resolver() {}
    5357                Resolver( const SymTab::Indexer & other ) {
     
    9599                CurrentObject currentObject = nullptr;
    96100                bool inEnumDecl = false;
     101                bool atTopLevel = false;  ///< Was this resolver set up at the top level of resolution
    97102        };
    98103
    99104        void resolve( std::list< Declaration * > translationUnit ) {
    100105                PassVisitor<Resolver> resolver;
     106                resolver.pass.atTopLevel = true;  // mark resolver as top-level
    101107                acceptAll( translationUnit, resolver );
    102108        }
     
    165171
    166172        namespace {
    167                 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {
     173                void findUnfinishedKindExpression( Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {
    168174                        assertf( untyped, "expected a non-null expression." );
    169175
     
    172178                        TypeEnvironment env;
    173179                        AlternativeFinder finder( indexer, env );
    174                         finder.find( untyped, adjust, prune, failFast );
     180                        finder.find( untyped, mode );
    175181
    176182                        #if 0
     
    218224
    219225                /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
    220                 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {
     226                void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {
    221227                        if ( ! untyped ) return;
    222228                        Alternative choice;
    223                         findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, adjust, prune, failFast );
     229                        findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );
    224230                        finishExpr( choice.expr, choice.env, untyped->env );
    225231                        untyped = choice.expr;
     
    250256                // set up and resolve expression cast to void
    251257                Alternative choice;
    252                 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, true );
     258                findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
    253259                CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
    254260                env = std::move( choice.env );
  • src/ResolvExpr/TypeEnvironment.cc

    r28f3a19 rb21c77a  
    77// TypeEnvironment.cc --
    88//
    9 // Author           : Richard C. Bilson
     9// Author           : Aaron B. Moss
    1010// Created On       : Sun May 17 12:19:47 2015
    1111// Last Modified By : Aaron B. Moss
    12 // Last Modified On : Mon Jun 18 11:58:00 2018
    13 // Update Count     : 4
     12// Last Modified On : Fri Jun 29 15:51:00 2018
     13// Update Count     : 5
    1414//
    1515
     
    1919#include <utility>                     // for pair, move
    2020
     21#include "Common/InternedString.h"     // for interned_string
    2122#include "Common/PassVisitor.h"        // for PassVisitor<GcTracer>
    2223#include "Common/utility.h"            // for maybeClone
     24#include "SymTab/Indexer.h"            // for Indexer
    2325#include "SynTree/GcTracer.h"          // for PassVisitor<GcTracer>
    2426#include "SynTree/Type.h"              // for Type, FunctionType, Type::Fora...
    2527#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
    26 #include "Tuples/Tuples.h"             // for isTtype
    2728#include "TypeEnvironment.h"
    2829#include "typeops.h"                   // for occurs
     
    4849        }
    4950
     51#if 0
    5052        void EqvClass::initialize( const EqvClass &src, EqvClass &dest ) {
    5153                initialize( src, dest, src.type );
     
    115117                return nullptr;
    116118        }
    117 
    118         /// Removes any class from env that intersects eqvClass
    119         void filterOverlappingClasses( std::list<EqvClass> &env, const EqvClass &eqvClass ) {
    120                 for ( auto i = env.begin(); i != env.end(); ) {
    121                         auto next = i;
    122                         ++next;
    123                         std::set<std::string> intersection;
    124                         std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(),
    125                                 std::inserter( intersection, intersection.begin() ) );
    126                         if ( ! intersection.empty() ) { env.erase( i ); }
    127                         i = next;
    128                 }
    129         }
    130 
    131         void TypeEnvironment::add( EqvClass &&eqvClass ) {
    132                 filterOverlappingClasses( env, eqvClass );
    133                 env.push_back( std::move(eqvClass) );
    134         }
    135 
    136         void TypeEnvironment::add( const Type::ForallList &tyDecls ) {
    137                 for ( Type::ForallList::const_iterator i = tyDecls.begin(); i != tyDecls.end(); ++i ) {
    138                         EqvClass newClass;
    139                         newClass.vars.insert( (*i)->get_name() );
    140                         newClass.data = TypeDecl::Data{ (*i) };
    141                         env.push_back( std::move(newClass) );
    142                 } // for
    143         }
    144 
    145         void TypeEnvironment::add( const TypeSubstitution & sub ) {
    146                 EqvClass newClass;
    147                 for ( auto p : sub ) {
    148                         newClass.vars.insert( p.first );
    149                         newClass.type = p.second->clone();
    150                         newClass.allowWidening = false;
    151                         // Minimal assumptions. Not technically correct, but might be good enough, and
    152                         // is the best we can do at the moment since information is lost in the
    153                         // transition to TypeSubstitution
    154                         newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false };
    155                         add( std::move(newClass) );
    156                 }
    157         }
    158 
    159         void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const {
    160                 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
    161                         for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) {
    162                                 if ( theClass->type ) {
    163                                         sub.add( *theVar, theClass->type );
    164                                 } else if ( theVar != theClass->vars.begin() ) {
    165                                         TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype );
    166                                         sub.add( *theVar, newTypeInst );
    167                                 } // if
    168                         } // for
    169                 } // for
    170                 sub.normalize();
    171         }
    172 
    173         void TypeEnvironment::print( std::ostream &os, Indenter indent ) const {
    174                 for ( const EqvClass & theClass : env ) {
    175                         theClass.print( os, indent );
    176                 } // for
    177         }
    178 
    179         std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
    180                 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) {
    181                         if ( i->vars.count( var ) ) return i;
    182                 } // for
    183                 return env.end();
    184         }
    185 
    186         void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) {
    187                 env.insert( env.end(), second.env.begin(), second.env.end() );
    188         }
    189 
    190         void TypeEnvironment::extractOpenVars( OpenVarSet &openVars ) const {
    191                 for ( std::list< EqvClass >::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) {
    192                         for ( std::set< std::string >::const_iterator var = eqvClass->vars.begin(); var != eqvClass->vars.end(); ++var ) {
    193                                 openVars[ *var ] = eqvClass->data;
    194                         } // for
    195                 } // for
    196         }
    197 
    198         void TypeEnvironment::addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ) {
    199                 for ( const EqvClass& c : actualEnv ) {
    200                         EqvClass c2 = c;
    201                         c2.allowWidening = false;
    202                         for ( const std::string& var : c2.vars ) {
    203                                 openVars[ var ] = c2.data;
    204                         }
    205                         env.push_back( std::move(c2) );
    206                 }
     119#endif
     120
     121        std::pair<interned_string, interned_string> TypeEnvironment::mergeClasses(
     122                        interned_string root1, interned_string root2 ) {
     123                // merge classes
     124                Classes* newClasses = classes->merge( root1, root2 );
     125
     126                // determine new root
     127                assertf(classes->get_mode() == Classes::REMFROM, "classes updated to REMFROM by merge");
     128                auto ret = std::make_pair( classes->get_root(), classes->get_child );
     129               
     130                // finalize classes
     131                classes = newClasses;
     132                return ret;
     133        }
     134
     135        ClassRef TypeEnvironment::lookup( interned_string var ) const {
     136                interned_string root = classes->find_or_default( var, nullptr );
     137                if ( root ) return { this, root };
     138                else return { nullptr, var };
    207139        }
    208140
     
    233165        }
    234166
    235         bool TypeEnvironment::bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    236                
     167        bool TypeEnvironment::bindVar( TypeInstType* typeInst, Type* bindTo,
     168                        const TypeDecl::Data& data, AssertionSet& need, AssertionSet& have,
     169                        const OpenVarSet& openVars, WidenMode widenMode, const SymTab::Indexer& indexer ) {
    237170                // remove references from other, so that type variables can only bind to value types
    238171                bindTo = bindTo->stripReferences();
    239                 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
    240                 assert( tyvar != openVars.end() );
    241                 if ( ! tyVarCompatible( tyvar->second, bindTo ) ) {
    242                         return false;
    243                 } // if
    244                 if ( occurs( bindTo, typeInst->get_name(), *this ) ) {
    245                         return false;
    246                 } // if
    247                 auto curClass = internal_lookup( typeInst->get_name() );
    248                 if ( curClass != env.end() ) {
    249                         if ( curClass->type ) {
    250                                 Type *common = 0;
    251                                 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to
    252                                 Type *newType = curClass->type->clone();
     172               
     173                auto tyVar = openVars.find( typeInst->get_name() );
     174                assert( tyVar != openVars.end() );
     175                if ( ! tyVarCompatible( tyVar->second, other ) ) return false;
     176
     177                if ( occurs( bindTo, typeInst->get_name(), *this ) ) return false;
     178
     179                if ( ClassRef curClass = lookup( typeInst->get_name() ) ) {
     180                        BoundType curData = curClass.get_bound();
     181                        if ( curData.type ) {
     182                                Type* common = nullptr;
     183                                // attempt to unify equivalence class type (which needs its qualifiers restored)
     184                                // with the target type
     185                                Type* newType = curData.type->clone();
    253186                                newType->get_qualifiers() = typeInst->get_qualifiers();
    254                                 if ( unifyInexact( newType, bindTo, *this, need, have, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {
     187                                if ( unifyInexact( newType, bindTo, *this, need, have, openVars,
     188                                                widenMode & WidenMode{ curData.allowWidening, true }, indexer, common ) ) {
    255189                                        if ( common ) {
     190                                                // update bound type to common type
    256191                                                common->get_qualifiers() = Type::Qualifiers{};
    257                                                 curClass->set_type( common );
    258                                         } // if
     192                                                curData.type = common;
     193                                                bindings = bindings->set( curClass.update_root(), curData );
     194                                        }
     195                                        return true;
    259196                                } else return false;
    260197                        } else {
    261                                 Type* newType = bindTo->clone();
    262                                 newType->get_qualifiers() = Type::Qualifiers{};
    263                                 curClass->set_type( newType );
    264                                 curClass->allowWidening = widenMode.widenFirst && widenMode.widenSecond;
    265                         } // if
     198                                // update bound type to other type
     199                                curData.type = bindTo->clone();
     200                                curData.type->get_qualifiers() = Type::Qualifiers{};
     201                                curData.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
     202                                bindings = bindings->set( curClass.get_root(), curData );
     203                        }
    266204                } else {
    267                         EqvClass newClass;
    268                         newClass.vars.insert( typeInst->get_name() );
    269                         newClass.type = bindTo->clone();
    270                         newClass.type->get_qualifiers() = Type::Qualifiers();
    271                         newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
    272                         newClass.data = data;
    273                         env.push_back( std::move(newClass) );
    274                 } // if
     205                        // make new class consisting entirely of this variable
     206                        BoundType curData{ bindTo->clone(), widenMode.first && widenMode.second, data };
     207                        curData.type->get_qualifiers() = Type::Qualifiers{};
     208                        classes = classes->add( curClass.get_root() );
     209                        bindings = bindings->set( curClass.get_root(), curData );
     210                }
    275211                return true;
    276212        }
    277 
    278         bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    279 
    280                 auto class1 = internal_lookup( var1->get_name() );
    281                 auto class2 = internal_lookup( var2->get_name() );
     213       
     214        bool TypeEnvironment::bindVarToVar( TypeInstType* var1, TypeInstType* var2,
     215                        const TypeDecl::Data& data, AssertionSet& need, AssertionSet& have,
     216                        const OpenVarSet& openVars, WidenMode widenMode, const SymTab::Indexer& indexer ) {
     217                ClassRef class1 = env.lookup( var1->get_name() );
     218                ClassRef class2 = env.lookup( var2->get_name() );
    282219               
    283220                // exit early if variables already bound together
    284                 if ( class1 != env.end() && class1 == class2 ) {
    285                         class1->allowWidening &= widenMode;
     221                if ( class1 && class2 && class1 == class2 ) {
     222                        BoundType data1 = class1.get_bound();
     223                        // narrow the binding if needed
     224                        if ( data1.allowWidening && widenMode.first != widenMode.second ) {
     225                                data1.allowWidening = false;
     226                                bindings = bindings->set( class1.get_root(), data1 );
     227                        }
    286228                        return true;
    287229                }
    288230
    289                 bool widen1 = false, widen2 = false;
    290                 const Type *type1 = nullptr, *type2 = nullptr;
    291 
    292                 // check for existing bindings, perform occurs check
    293                 if ( class1 != env.end() ) {
    294                         if ( class1->type ) {
    295                                 if ( occurs( class1->type, var2->get_name(), *this ) ) return false;
    296                                 type1 = class1->type;
    297                         } // if
    298                         widen1 = widenMode.widenFirst && class1->allowWidening;
    299                 } // if
    300                 if ( class2 != env.end() ) {
    301                         if ( class2->type ) {
    302                                 if ( occurs( class2->type, var1->get_name(), *this ) ) return false;
    303                                 type2 = class2->type;
    304                         } // if
    305                         widen2 = widenMode.widenSecond && class2->allowWidening;
    306                 } // if
    307 
    308                 if ( type1 && type2 ) {
    309                         // both classes bound, merge if bound types can be unified
    310                         Type *newType1 = type1->clone(), *newType2 = type2->clone();
    311                         WidenMode newWidenMode{ widen1, widen2 };
    312                         Type *common = 0;
    313                         if ( unifyInexact( newType1, newType2, *this, need, have, openVars, newWidenMode, indexer, common ) ) {
    314                                 class1->vars.insert( class2->vars.begin(), class2->vars.end() );
    315                                 class1->allowWidening = widen1 && widen2;
     231                BoundType data1 = class1 ? class1.get_bound() : BoundType{};
     232                BoundType data2 = class2 ? class2.get_bound() : BoundType{};
     233
     234                bool widen1 = data1.allowWidening && widenMode.widenFirst;
     235                bool widen2 = data2.allowWidening && widenMode.widenSecond;
     236
     237                if ( data1.type && data2.type ) {
     238                        // attempt to unify bound classes
     239                        Type* common = nullptr;
     240                        if ( unifyInexact( data1.type->clone(), data2.type->clone(), *this, need, have,
     241                                        openVars, WidenMode{ widen1, widen2 }, indexer, common ) ) {
     242                                // merge type variables
     243                                interned_string root = mergeClasses( class1.update_root(), class2.update_root() );
     244                                // update bindings
     245                                data1.allowWidening = widen1 && widen2;
    316246                                if ( common ) {
    317247                                        common->get_qualifiers() = Type::Qualifiers{};
    318                                         class1->set_type( common );
     248                                        data1.type = common;
    319249                                }
    320                                 env.erase( class2 );
     250                                bindings = bindings->set( root, data1 );
    321251                        } else return false;
    322                 } else if ( class1 != env.end() && class2 != env.end() ) {
    323                         // both classes exist, at least one unbound, merge unconditionally
    324                         if ( type1 ) {
    325                                 class1->vars.insert( class2->vars.begin(), class2->vars.end() );
    326                                 class1->allowWidening = widen1;
    327                                 env.erase( class2 );
    328                         } else {
    329                                 class2->vars.insert( class1->vars.begin(), class1->vars.end() );
    330                                 class2->allowWidening = widen2;
    331                                 env.erase( class1 );
    332                         } // if
    333                 } else if ( class1 != env.end() ) {
    334                         // var2 unbound, add to class1
    335                         class1->vars.insert( var2->get_name() );
    336                         class1->allowWidening = widen1;
    337                 } else if ( class2 != env.end() ) {
    338                         // var1 unbound, add to class2
    339                         class2->vars.insert( var1->get_name() );
    340                         class2->allowWidening = widen2;
     252                } else if ( class1 && class2 ) {
     253                        // both classes exist, only one bound -- merge type variables
     254                        auto merged = mergeClasses( class1.get_root(), class2.get_root() );
     255                        // remove subordinate binding
     256                        bindings = bindings->erase( merged.second );
     257                        // update root binding (narrow widening as needed, or set new binding for changed root)
     258                        if ( data1.type ) {
     259                                if ( data1.allowWidening != widen1 ) {
     260                                        data1.allowWidening = widen1;
     261                                        bindings = bindings->set( merged.first, data1 );
     262                                } else if ( merged.first == class2.get_root() ) {
     263                                        bindings = bindings->set( merged.first, data1 );
     264                                }
     265                        } else /* if ( data2.type ) */ {
     266                                if ( data2.allowWidening != widen2 ) {
     267                                        data2.allowWidening = widen2;
     268                                        bindings = bindings->set( root, data2 );
     269                                } else if ( merged.first == class1.get_root() ) {
     270                                        bindings = bindings->set( merged.first, data2 );
     271                                }
     272                        }
     273                } else if ( class1 ) {
     274                        // add unbound var2 to class1
     275                        classes = classes->add( class2.get_root() );
     276                        auto merged = mergeClasses( class1.get_root(), class2.get_root() );
     277                        // update bindings (narrow as needed, or switch binding to root)
     278                        if ( merged.first == class2.get_root() ) {
     279                                data1.allowWidening = widen1;
     280                                bindings = bindings->erase( merged.second )->set( merged.first, data1 );
     281                        } else if ( data1.allowWidening != widen1 ) {
     282                                bindings = bindings->set( merged.first, data1 );
     283                        }
     284                } else if ( class2 ) {
     285                        // add unbound var1 to class1
     286                        classes = classes->add( class1.get_root() );
     287                        auto merged = mergeClasses( class1.get_root(), class2.get_root() );
     288                        // update bindings (narrow as needed, or switch binding to root)
     289                        if ( merged.first == class1.get_root() ) {
     290                                data2.allowWidening = widen2;
     291                                bindings = bindings->erase( merged.second )->set( merged.first, data2 );
     292                        } else if ( data2.allowWidening != widen2 ) {
     293                                bindings = bindings->set( merged.first, data2 );
     294                        }
    341295                } else {
    342                         // neither var bound, create new class
     296                        // make new class with pair of unbound vars
     297                        classes = classes->add( class1.get_root() )->add( class2.get_root() );
     298                        auto merged = mergeClasses( class1.get_root(), class2.get_root() );
     299                        bindings = bindings->set( merged.first, BoundType{ nullptr, widen1 && widen2, data } );
     300                }
     301                return true;
     302        }
     303
     304#if !1
     305        /// Removes any class from env that intersects eqvClass
     306        void filterOverlappingClasses( std::list<EqvClass> &env, const EqvClass &eqvClass ) {
     307                for ( auto i = env.begin(); i != env.end(); ) {
     308                        auto next = i;
     309                        ++next;
     310                        std::set<std::string> intersection;
     311                        std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(),
     312                                std::inserter( intersection, intersection.begin() ) );
     313                        if ( ! intersection.empty() ) { env.erase( i ); }
     314                        i = next;
     315                }
     316        }
     317
     318        void TypeEnvironment::add( EqvClass &&eqvClass ) {
     319                filterOverlappingClasses( env, eqvClass );
     320                env.push_back( std::move(eqvClass) );
     321        }
     322
     323        void TypeEnvironment::add( const Type::ForallList &tyDecls ) {
     324                for ( Type::ForallList::const_iterator i = tyDecls.begin(); i != tyDecls.end(); ++i ) {
    343325                        EqvClass newClass;
    344                         newClass.vars.insert( var1->get_name() );
    345                         newClass.vars.insert( var2->get_name() );
    346                         newClass.allowWidening = widen1 && widen2;
    347                         newClass.data = data;
     326                        newClass.vars.insert( (*i)->get_name() );
     327                        newClass.data = TypeDecl::Data{ (*i) };
    348328                        env.push_back( std::move(newClass) );
    349                 } // if
    350                 return true;
    351         }
    352 
    353         void TypeEnvironment::forbidWidening() {
    354                 for ( EqvClass& c : env ) c.allowWidening = false;
     329                } // for
     330        }
     331
     332        void TypeEnvironment::add( const TypeSubstitution & sub ) {
     333                EqvClass newClass;
     334                for ( auto p : sub ) {
     335                        newClass.vars.insert( p.first );
     336                        newClass.type = p.second->clone();
     337                        newClass.allowWidening = false;
     338                        // Minimal assumptions. Not technically correct, but might be good enough, and
     339                        // is the best we can do at the moment since information is lost in the
     340                        // transition to TypeSubstitution
     341                        newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false };
     342                        add( std::move(newClass) );
     343                }
     344        }
     345
     346        void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const {
     347                for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
     348                        for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) {
     349                                if ( theClass->type ) {
     350                                        sub.add( *theVar, theClass->type );
     351                                } else if ( theVar != theClass->vars.begin() ) {
     352                                        TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype );
     353                                        sub.add( *theVar, newTypeInst );
     354                                } // if
     355                        } // for
     356                } // for
     357                sub.normalize();
     358        }
     359
     360        void TypeEnvironment::print( std::ostream &os, Indenter indent ) const {
     361                for ( const EqvClass & theClass : env ) {
     362                        theClass.print( os, indent );
     363                } // for
     364        }
     365
     366        std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
     367                for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) {
     368                        if ( i->vars.count( var ) ) return i;
     369                } // for
     370                return env.end();
     371        }
     372
     373        void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) {
     374                env.insert( env.end(), second.env.begin(), second.env.end() );
     375        }
     376
     377        void TypeEnvironment::extractOpenVars( OpenVarSet &openVars ) const {
     378                for ( std::list< EqvClass >::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) {
     379                        for ( std::set< std::string >::const_iterator var = eqvClass->vars.begin(); var != eqvClass->vars.end(); ++var ) {
     380                                openVars[ *var ] = eqvClass->data;
     381                        } // for
     382                } // for
     383        }
     384
     385        void TypeEnvironment::addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ) {
     386                for ( const EqvClass& c : actualEnv ) {
     387                        EqvClass c2 = c;
     388                        c2.allowWidening = false;
     389                        for ( const std::string& var : c2.vars ) {
     390                                openVars[ var ] = c2.data;
     391                        }
     392                        env.push_back( std::move(c2) );
     393                }
    355394        }
    356395
     
    359398                return out;
    360399        }
     400#endif
    361401
    362402        PassVisitor<GcTracer> & operator<<( PassVisitor<GcTracer> & gc, const TypeEnvironment & env ) {
    363                 for ( const EqvClass & c : env ) {
    364                         maybeAccept( c.type, gc );
     403                for ( ClassRef c : env ) {
     404                        maybeAccept( c.get_bound().type, gc );
    365405                }
    366406                return gc;
  • src/ResolvExpr/TypeEnvironment.h

    r28f3a19 rb21c77a  
    77// TypeEnvironment.h --
    88//
    9 // Author           : Richard C. Bilson
     9// Author           : Aaron B. Moss
    1010// Created On       : Sun May 17 12:24:58 2015
    1111// Last Modified By : Aaron B. Moss
    12 // Last Modified On : Mon Jun 18 11:58:00 2018
    13 // Update Count     : 4
     12// Last Modified On : Fri Jun 29 16:00:00 2018
     13// Update Count     : 5
    1414//
    1515
    1616#pragma once
    1717
    18 #include <iostream>                    // for ostream
    19 #include <list>                        // for list, list<>::iterator, list<>...
    20 #include <map>                         // for map, map<>::value_compare
    21 #include <set>                         // for set
    22 #include <string>                      // for string
    23 #include <utility>                     // for move, swap
     18#include <iostream>                        // for ostream
     19#include <iterator>
     20#include <list>                            // for list, list<>::iterator, list<>...
     21#include <map>                             // for map, map<>::value_compare
     22#include <set>                             // for set
     23#include <string>                          // for string
     24#include <utility>                         // for pair
     25#include <vector>                          // for vector
    2426
    2527#include "WidenMode.h"                 // for WidenMode
    2628
    27 #include "SynTree/Declaration.h"       // for TypeDecl::Data, DeclarationWit...
    28 #include "SynTree/SynTree.h"           // for UniqueId
    29 #include "SynTree/Type.h"              // for Type, Type::ForallList
    30 #include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
    31 
    32 template< typename Pass >
    33 class PassVisitor;
     29#include "Common/InternedString.h"         // for interned_string
     30#include "Common/PersistentDisjointSet.h"  // for PersistentDisjointSet
     31#include "Common/PersistentMap.h"          // for PersistentMap
     32#include "SynTree/Declaration.h"           // for TypeDecl::Data, DeclarationWit...
     33#include "SynTree/SynTree.h"               // for UniqueId
     34#include "SynTree/Type.h"                  // for Type, TypeInstType, Type::ForallList
     35#include "SynTree/TypeSubstitution.h"      // for TypeSubstitution
     36
     37template< typename Pass > class PassVisitor;
    3438class GcTracer;
     39namespace SymTab { class Indexer; }
    3540
    3641namespace ResolvExpr {
     
    4348        // declarations.
    4449        //
    45         // I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this comparator.
     50        // I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
     51        // comparator.
    4652        //
    4753        // Note: since this compares pointers for position, minor changes in the source file that affect
    4854        // memory layout can alter compilation time in unpredictable ways. For example, the placement
    4955        // of a line directive can reorder type pointers with respect to each other so that assertions
    50         // are seen in different orders, causing a potentially different number of unification calls when
    51         // resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering line directives
    52         // alone, so it would be nice to fix this comparison so that assertions compare more consistently.
    53         // I've tried to modify this to compare on mangle name instead of type as the second comparator, but
    54         // this causes some assertions to never be recorded. More investigation is needed.
     56        // are seen in different orders, causing a potentially different number of unification calls
     57        // when resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering
     58        // line directives alone, so it would be nice to fix this comparison so that assertions compare
     59        // more consistently. I've tried to modify this to compare on mangle name instead of type as
     60        // the second comparator, but this causes some assertions to never be recorded. More
     61        // investigation is needed.
    5562        struct AssertCompare {
    5663                bool operator()( DeclarationWithType * d1, DeclarationWithType * d2 ) const {
     
    6269        struct AssertionSetValue {
    6370                bool isUsed;
    64                 // chain of Unique IDs of the assertion declarations. The first ID in the chain is the ID of an assertion on the current type,
    65                 // with each successive ID being the ID of an assertion pulled in by the previous ID. The last ID in the chain is
    66                 // the ID of the assertion that pulled in the current assertion.
     71                // chain of Unique IDs of the assertion declarations. The first ID in the chain is the ID
     72                // of an assertion on the current type, with each successive ID being the ID of an
     73                // assertion pulled in by the previous ID. The last ID in the chain is the ID of the
     74                // assertion that pulled in the current assertion.
    6775                std::list< UniqueId > idChain;
    6876        };
     
    7381        void printOpenVarSet( const OpenVarSet &, std::ostream &, int indent = 0 );
    7482
     83        /// A data structure for holding all the necessary information for a type binding
     84        struct BoundType {
     85                Type* type;
     86                bool allowWidening;
     87                TypeDecl::Data data;
     88        };
     89
     90#if 0
     91        /// An equivalence class, with its binding information
    7592        struct EqvClass {
    7693                std::set< std::string > vars;
     
    92109                void set_type(Type* ty);
    93110        };
     111#endif
     112       
     113        class TypeEnvironment;
     114
     115        /// A reference to an equivalence class that may be used to constitute one from its environment
     116        class ClassRef {
     117                friend TypeEnvironment;
     118
     119                const TypeEnvironment* env;  ///< Containing environment
     120                interned_string root;        ///< Name of root type
     121
     122        public:
     123                ClassRef() : env(nullptr), root(nullptr) {}
     124                ClassRef( const TypeEnvironment* env, interned_string root ) : env(env), root(root) {}
     125
     126                /// Gets the root of the reference equivalence class;
     127                interned_string get_root() const { return root; }
     128
     129                /// Ensures that root is still the representative element of this typeclass;
     130                /// undefined behaviour if called without referenced typeclass; returns new root
     131                inline interned_string update_root();
     132
     133                /// Gets the type variables of the referenced equivalence class, empty list for none
     134                template<typename T = std::vector<interned_string>>
     135                inline T get_vars() const;
     136
     137                /// Gets the bound type information of the referenced equivalence class, default if none
     138                inline BoundType get_bound() const;
     139
     140#if 0
     141                /// Gets the referenced equivalence class
     142                inline EqvClass get_class() const;
     143                EqvClass operator* () const { return get_class(); }
     144#endif
     145
     146                // Check that there is a referenced typeclass
     147                explicit operator bool() const { return env != nullptr; }
     148
     149                bool operator== (const ClassRef& o) const { return env == o.env && root == o.root; }
     150                bool operator!= (const ClassRef& o) const { return !(*this == o); }
     151        };
    94152
    95153        class TypeEnvironment {
     154                friend ClassRef;
     155
     156                /// Backing storage for equivalence classes
     157                using Classes = PersistentDisjointSet<interned_string>;
     158                /// Type bindings included in this environment (from class root)
     159                using Bindings = PersistentMap<interned_string, BoundType>;
     160
     161                /// Sets of equivalent type variables, stored by name
     162                Classes* classes;
     163                /// Bindings from roots of equivalence classes to type binding information.
     164                /// All roots have a binding so that the list of classes can be reconstituted, though these
     165                /// may be null.
     166                Bindings* bindings;
     167
     168                /// Merges the classes rooted at root1 and root2, returning a pair containing the root and
     169                /// child of the bound class. Does not check for validity of merge.
     170                std::pair<interned_string, interned_string> mergeClasses(
     171                        interned_string root1, interned_string root2 );
     172
    96173          public:
    97                 const EqvClass* lookup( const std::string &var ) const;
    98           private:
    99                 void add( EqvClass &&eqvClass  );
    100           public:
     174                class iterator : public std::iterator<
     175                                std::forward_iterator_tag,
     176                                ClassRef,
     177                                std::iterator_traits<Bindings::iterator>::difference_type,
     178                                ClassRef,
     179                                ClassRef> {
     180                        friend TypeEnvironment;
     181                       
     182                        const TypeEnvironment* env;
     183                        Bindings::iterator it;
     184
     185                        iterator(const TypeEnvironment* e, Bindings::iterator&& i) : env(e), it(std::move(i)) {}
     186
     187                        ClassRef ref() const { return { env, it->first }; }
     188                public:
     189                        iterator() = default;
     190
     191                        reference operator* () { return ref(); }
     192                        pointer operator-> () { return ref(); }
     193
     194                        iterator& operator++ () { ++it; return *this; }
     195                        iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
     196
     197                        bool operator== (const iterator& o) const { return env == o.env && it == o.it; }
     198                        bool operator!= (const iterator& o) const { return !(*this == o); }
     199                };
     200
     201                /// Finds a reference to the class containing `var`, invalid if none such.
     202                /// returned root variable will be valid regardless
     203                ClassRef lookup( interned_string var ) const;
     204                ClassRef lookup( const std::string &var ) const { return lookup( var ); }
     205
     206                /// Binds a type variable to a type; returns false if fails
     207                bool bindVar( TypeInstType* typeInst, Type* bindTo, const TypeDecl::Data& data,
     208                        AssertionSet& need, AssertionSet& have, const OpenVarSet& openVars,
     209                        WidenMode widenMode, const SymTab::Indexer& indexer );
     210               
     211                /// Binds two type variables together; returns false if fails
     212                bool bindVarToVar( TypeInstType* var1, TypeInstType* var2, const TypeDecl::Data& data,
     213                        AssertionSet& need, AssertionSet& have, const OpenVarSet& openVars,
     214                        WidenMode widenMode, const SymTab::Indexer& indexer );
     215#if !1
     216        private:
     217                void add( EqvClass &&eqvClass );
     218        public:
    101219                void add( const Type::ForallList &tyDecls );
    102220                void add( const TypeSubstitution & sub );
     
    104222                template< typename SynTreeClass > int applyFree( SynTreeClass *&type ) const;
    105223                void makeSubstitution( TypeSubstitution &result ) const;
    106                 bool isEmpty() const { return env.empty(); }
     224#endif
     225                bool isEmpty() const { return classes->empty(); }
     226#if !1
    107227                void print( std::ostream &os, Indenter indent = {} ) const;
    108                 // void combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) );
    109228                void simpleCombine( const TypeEnvironment &second );
    110229                void extractOpenVars( OpenVarSet &openVars ) const;
     230#endif
    111231                TypeEnvironment *clone() const { return new TypeEnvironment( *this ); }
    112232
     233#if !1
    113234                /// Iteratively adds the environment of a new actual (with allowWidening = false),
    114235                /// and extracts open variables.
    115236                void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars );
    116237
    117                 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add
    118                 /// the class if needed. Returns false on failure.
    119                 bool bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
    120                
    121                 /// Binds the type classes represented by `var1` and `var2` together; will add
    122                 /// one or both classes if needed. Returns false on failure.
    123                 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
    124 
    125238                /// Disallows widening for all bindings in the environment
    126239                void forbidWidening();
    127 
    128                 using iterator = std::list< EqvClass >::const_iterator;
    129                 iterator begin() const { return env.begin(); }
    130                 iterator end() const { return env.end(); }
    131 
    132           private:
    133                 std::list< EqvClass > env;
    134                
    135                 std::list< EqvClass >::iterator internal_lookup( const std::string &var );
    136         };
     240#endif
     241
     242                iterator begin() { return { this, bindings->begin() }; }
     243                iterator end() { return { this, bindings->end() }; }
     244        };
     245
     246        void ClassRef::update_root() { return root = env->classes->find( root ); }
     247
     248        template<typename T>
     249        T ClassRef::get_vars() const {
     250                T vars;
     251                env->classes->find_class( root, std::inserter(vars, vars.end()) );
     252                return vars;
     253        }
     254
     255        BoundType ClassRef::get_bound() const {
     256                return env->bindings->get_or_default( root, BoundType{} );
     257        }
     258
     259#if 0
     260        EqvClass ClassRef::get_class() const { return { get_vars(), get_bound() }; }
     261#endif
    137262
    138263        template< typename SynTreeClass >
     
    150275        }
    151276
     277#if !1
    152278        std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env );
     279#endif
    153280
    154281        PassVisitor<GcTracer> & operator<<( PassVisitor<GcTracer> & gc, const TypeEnvironment & env );
  • src/ResolvExpr/Unify.cc

    r28f3a19 rb21c77a  
    3131#include "SynTree/Visitor.h"      // for Visitor
    3232#include "Tuples/Tuples.h"        // for isTtype
    33 #include "TypeEnvironment.h"      // for EqvClass, AssertionSet, OpenVarSet
     33#include "TypeEnvironment.h"      // for ClassRef, AssertionSet, OpenVarSet
    3434#include "Unify.h"
    3535#include "typeops.h"              // for flatten, occurs, commonType
     
    377377                void premutate( TypeInstType * ) { visit_children = false; }
    378378                Type * postmutate( TypeInstType * typeInst ) {
    379                         if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {
     379                        if ( ClassRef eqvClass = tenv.lookup( typeInst->get_name() ) ) {
    380380                                // expand ttype parameter into its actual type
    381                                 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {
    382                                         return eqvClass->type->clone();
     381                                BoundType cBound = eqvClass.get_bound();
     382                                if ( cBound.data.kind == TypeDecl::Ttype && cBound.type ) {
     383                                        return cBound.type->clone();
    383384                                }
    384385                        }
Note: See TracChangeset for help on using the changeset viewer.