Ignore:
Timestamp:
Aug 27, 2018, 4:40:34 PM (7 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
b7c89aa
Parents:
f9feab8 (diff), 305581d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into cleanup-dtors

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/TypeEnvironment.cc

    rf9feab8 r90152a4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:19:47 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun May 17 12:23:36 2015
    13 // Update Count     : 3
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 18 11:58:00 2018
     13// Update Count     : 4
    1414//
    1515
     
    1717#include <algorithm>                   // for copy, set_intersection
    1818#include <iterator>                    // for ostream_iterator, insert_iterator
    19 #include <utility>                     // for pair
     19#include <memory>                      // for unique_ptr
     20#include <utility>                     // for pair, move
    2021
    2122#include "Common/utility.h"            // for maybeClone
    2223#include "SynTree/Type.h"              // for Type, FunctionType, Type::Fora...
    2324#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
     25#include "Tuples/Tuples.h"             // for isTtype
    2426#include "TypeEnvironment.h"
     27#include "typeops.h"                   // for occurs
     28#include "Unify.h"                     // for unifyInexact
    2529
    2630namespace ResolvExpr {
     
    4448
    4549        void EqvClass::initialize( const EqvClass &src, EqvClass &dest ) {
     50                initialize( src, dest, src.type );
     51        }
     52
     53        void EqvClass::initialize( const EqvClass &src, EqvClass &dest, const Type *ty ) {
    4654                dest.vars = src.vars;
    47                 dest.type = maybeClone( src.type );
     55                dest.type = maybeClone( ty );
    4856                dest.allowWidening = src.allowWidening;
    4957                dest.data = src.data;
    5058        }
    5159
    52         EqvClass::EqvClass() : type( 0 ), allowWidening( true ) {
     60        EqvClass::EqvClass() : type( nullptr ), allowWidening( true ) {
    5361        }
    5462
    5563        EqvClass::EqvClass( const EqvClass &other ) {
    5664                initialize( other, *this );
     65        }
     66
     67        EqvClass::EqvClass( const EqvClass &other, const Type *ty ) {
     68                initialize( other, *this, ty );
     69        }
     70
     71        EqvClass::EqvClass( EqvClass &&other )
     72        : vars{std::move(other.vars)}, type{other.type},
     73          allowWidening{std::move(other.allowWidening)}, data{std::move(other.data)} {
     74                  other.type = nullptr;
    5775        }
    5876
     
    6482        }
    6583
     84        EqvClass &EqvClass::operator=( EqvClass &&other ) {
     85                if ( this == &other ) return *this;
     86                delete type;
     87
     88                vars = std::move(other.vars);
     89                type = other.type;
     90                other.type = nullptr;
     91                allowWidening = std::move(other.allowWidening);
     92                data = std::move(other.data);
     93
     94                return *this;
     95        }
     96
    6697        EqvClass::~EqvClass() {
    6798                delete type;
     99        }
     100
     101        void EqvClass::set_type( Type* ty ) {
     102                if ( ty == type ) return;
     103                delete type;
     104                type = ty;
    68105        }
    69106
     
    82119        }
    83120
    84         bool TypeEnvironment::lookup( const std::string &var, EqvClass &eqvClass ) const {
     121        const EqvClass* TypeEnvironment::lookup( const std::string &var ) const {
    85122                for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) {
    86                         if ( i->vars.find( var ) != i->vars.end() ) {
    87 ///       std::cout << var << " is in class ";
    88 ///       i->print( std::cout );
    89                                 eqvClass = *i;
    90                                 return true;
    91                         }
    92 ///     std::cout << var << " is not in class ";
    93 ///     i->print( std::cout );
    94                 } // for
    95                 return false;
    96         }
    97 
    98         void TypeEnvironment::add( const EqvClass &eqvClass ) {
    99                 std::list< EqvClass >::iterator i = env.begin();
    100                 while ( i != env.end() ) {
    101                         std::list< EqvClass >::iterator next = i;
    102                         next++;
    103                         std::set< std::string > intersection;
    104                         std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), std::inserter( intersection, intersection.begin() ) );
    105                         if ( ! intersection.empty() ) {
    106                                 env.erase( i );
    107                         } // if
     123                        if ( i->vars.find( var ) != i->vars.end() ) return &*i;
     124                } // for
     125                return nullptr;
     126        }
     127
     128        /// Removes any class from env that intersects eqvClass
     129        void filterOverlappingClasses( std::list<EqvClass> &env, const EqvClass &eqvClass ) {
     130                for ( auto i = env.begin(); i != env.end(); ) {
     131                        auto next = i;
     132                        ++next;
     133                        std::set<std::string> intersection;
     134                        std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(),
     135                                std::inserter( intersection, intersection.begin() ) );
     136                        if ( ! intersection.empty() ) { env.erase( i ); }
    108137                        i = next;
    109                 } // while
    110                 env.insert( env.end(), eqvClass );
     138                }
     139        }
     140
     141        void TypeEnvironment::add( EqvClass &&eqvClass ) {
     142                filterOverlappingClasses( env, eqvClass );
     143                env.push_back( std::move(eqvClass) );
    111144        }
    112145
     
    116149                        newClass.vars.insert( (*i)->get_name() );
    117150                        newClass.data = TypeDecl::Data{ (*i) };
    118                         env.push_back( newClass );
    119                 } // for
     151                        env.push_back( std::move(newClass) );
     152                } // for
     153        }
     154
     155        void TypeEnvironment::add( const TypeSubstitution & sub ) {
     156                EqvClass newClass;
     157                for ( auto p : sub ) {
     158                        newClass.vars.insert( p.first );
     159                        newClass.type = p.second->clone();
     160                        newClass.allowWidening = false;
     161                        // Minimal assumptions. Not technically correct, but might be good enough, and
     162                        // is the best we can do at the moment since information is lost in the
     163                        // transition to TypeSubstitution
     164                        newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false };
     165                        add( std::move(newClass) );
     166                }
    120167        }
    121168
     
    123170                for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
    124171                        for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) {
    125 ///       std::cerr << "adding " << *theVar;
    126172                                if ( theClass->type ) {
    127 ///         std::cerr << " bound to ";
    128 ///         theClass->type->print( std::cerr );
    129 ///         std::cerr << std::endl;
    130173                                        sub.add( *theVar, theClass->type );
    131174                                } else if ( theVar != theClass->vars.begin() ) {
    132175                                        TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype );
    133 ///         std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl;
    134176                                        sub.add( *theVar, newTypeInst );
    135177                                        delete newTypeInst;
     
    137179                        } // for
    138180                } // for
    139 ///   std::cerr << "input env is:" << std::endl;
    140 ///   print( std::cerr, 8 );
    141 ///   std::cerr << "sub is:" << std::endl;
    142 ///   sub.print( std::cerr, 8 );
    143181                sub.normalize();
    144182        }
    145183
    146184        void TypeEnvironment::print( std::ostream &os, Indenter indent ) const {
    147                 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) {
    148                         i->print( os, indent );
     185                for ( const EqvClass & theClass : env ) {
     186                        theClass.print( os, indent );
    149187                } // for
    150188        }
     
    152190        std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
    153191                for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) {
    154                         if ( i->vars.find( var ) == i->vars.end() ) {
    155                                 return i;
    156                         } // if
     192                        if ( i->vars.count( var ) ) return i;
    157193                } // for
    158194                return env.end();
     
    161197        void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) {
    162198                env.insert( env.end(), second.env.begin(), second.env.end() );
    163         }
    164 
    165         void TypeEnvironment::combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) ) {
    166                 TypeEnvironment secondCopy( second );
    167                 for ( std::list< EqvClass >::iterator firstClass = env.begin(); firstClass != env.end(); ++firstClass ) {
    168                         EqvClass &newClass = *firstClass;
    169                         std::set< std::string > newVars;
    170                         for ( std::set< std::string >::const_iterator var = firstClass->vars.begin(); var != firstClass->vars.end(); ++var ) {
    171                                 std::list< EqvClass >::iterator secondClass = secondCopy.internal_lookup( *var );
    172                                 if ( secondClass != secondCopy.env.end() ) {
    173                                         newVars.insert( secondClass->vars.begin(), secondClass->vars.end() );
    174                                         if ( secondClass->type ) {
    175                                                 if ( newClass.type ) {
    176                                                         Type *newType = combineFunc( newClass.type, secondClass->type );
    177                                                         delete newClass.type;
    178                                                         newClass.type = newType;
    179                                                         newClass.allowWidening = newClass.allowWidening && secondClass->allowWidening;
    180                                                 } else {
    181                                                         newClass.type = secondClass->type->clone();
    182                                                         newClass.allowWidening = secondClass->allowWidening;
    183                                                 } // if
    184                                         } // if
    185                                         secondCopy.env.erase( secondClass );
    186                                 } // if
    187                         } // for
    188                         newClass.vars.insert( newVars.begin(), newVars.end() );
    189                 } // for
    190                 for ( std::list< EqvClass >::iterator secondClass = secondCopy.env.begin(); secondClass != secondCopy.env.end(); ++secondClass ) {
    191                         env.push_back( *secondClass );
    192                 } // for
    193199        }
    194200
     
    212218        }
    213219
     220        bool isFtype( Type *type ) {
     221                if ( dynamic_cast< FunctionType* >( type ) ) {
     222                        return true;
     223                } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {
     224                        return typeInst->get_isFtype();
     225                } // if
     226                return false;
     227        }
     228
     229        bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {
     230                switch ( data.kind ) {
     231                  case TypeDecl::Dtype:
     232                        // to bind to an object type variable, the type must not be a function type.
     233                        // if the type variable is specified to be a complete type then the incoming
     234                        // type must also be complete
     235                        // xxx - should this also check that type is not a tuple type and that it's not a ttype?
     236                        return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
     237                  case TypeDecl::Ftype:
     238                        return isFtype( type );
     239                  case TypeDecl::Ttype:
     240                        // ttype unifies with any tuple type
     241                        return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );
     242                  default:
     243                        assertf(false, "Unhandled tyvar kind: %d", data.kind);
     244                } // switch
     245                return false;
     246        }
     247
     248        bool TypeEnvironment::bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     249
     250                // remove references from other, so that type variables can only bind to value types
     251                bindTo = bindTo->stripReferences();
     252                OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
     253                assert( tyvar != openVars.end() );
     254                if ( ! tyVarCompatible( tyvar->second, bindTo ) ) {
     255                        return false;
     256                } // if
     257                if ( occurs( bindTo, typeInst->get_name(), *this ) ) {
     258                        return false;
     259                } // if
     260                auto curClass = internal_lookup( typeInst->get_name() );
     261                if ( curClass != env.end() ) {
     262                        if ( curClass->type ) {
     263                                Type *common = 0;
     264                                // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to
     265                                std::unique_ptr< Type > newType( curClass->type->clone() );
     266                                newType->get_qualifiers() = typeInst->get_qualifiers();
     267                                if ( unifyInexact( newType.get(), bindTo, *this, need, have, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {
     268                                        if ( common ) {
     269                                                common->get_qualifiers() = Type::Qualifiers{};
     270                                                curClass->set_type( common );
     271                                        } // if
     272                                } else return false;
     273                        } else {
     274                                Type* newType = bindTo->clone();
     275                                newType->get_qualifiers() = Type::Qualifiers{};
     276                                curClass->set_type( newType );
     277                                curClass->allowWidening = widenMode.widenFirst && widenMode.widenSecond;
     278                        } // if
     279                } else {
     280                        EqvClass newClass;
     281                        newClass.vars.insert( typeInst->get_name() );
     282                        newClass.type = bindTo->clone();
     283                        newClass.type->get_qualifiers() = Type::Qualifiers();
     284                        newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
     285                        newClass.data = data;
     286                        env.push_back( std::move(newClass) );
     287                } // if
     288                return true;
     289        }
     290
     291        bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     292
     293                auto class1 = internal_lookup( var1->get_name() );
     294                auto class2 = internal_lookup( var2->get_name() );
     295
     296                // exit early if variables already bound together
     297                if ( class1 != env.end() && class1 == class2 ) {
     298                        class1->allowWidening &= widenMode;
     299                        return true;
     300                }
     301
     302                bool widen1 = false, widen2 = false;
     303                const Type *type1 = nullptr, *type2 = nullptr;
     304
     305                // check for existing bindings, perform occurs check
     306                if ( class1 != env.end() ) {
     307                        if ( class1->type ) {
     308                                if ( occurs( class1->type, var2->get_name(), *this ) ) return false;
     309                                type1 = class1->type;
     310                        } // if
     311                        widen1 = widenMode.widenFirst && class1->allowWidening;
     312                } // if
     313                if ( class2 != env.end() ) {
     314                        if ( class2->type ) {
     315                                if ( occurs( class2->type, var1->get_name(), *this ) ) return false;
     316                                type2 = class2->type;
     317                        } // if
     318                        widen2 = widenMode.widenSecond && class2->allowWidening;
     319                } // if
     320
     321                if ( type1 && type2 ) {
     322                        // both classes bound, merge if bound types can be unified
     323                        std::unique_ptr<Type> newType1{ type1->clone() }, newType2{ type2->clone() };
     324                        WidenMode newWidenMode{ widen1, widen2 };
     325                        Type *common = 0;
     326                        if ( unifyInexact( newType1.get(), newType2.get(), *this, need, have, openVars, newWidenMode, indexer, common ) ) {
     327                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
     328                                class1->allowWidening = widen1 && widen2;
     329                                if ( common ) {
     330                                        common->get_qualifiers() = Type::Qualifiers{};
     331                                        class1->set_type( common );
     332                                }
     333                                env.erase( class2 );
     334                        } else return false;
     335                } else if ( class1 != env.end() && class2 != env.end() ) {
     336                        // both classes exist, at least one unbound, merge unconditionally
     337                        if ( type1 ) {
     338                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
     339                                class1->allowWidening = widen1;
     340                                env.erase( class2 );
     341                        } else {
     342                                class2->vars.insert( class1->vars.begin(), class1->vars.end() );
     343                                class2->allowWidening = widen2;
     344                                env.erase( class1 );
     345                        } // if
     346                } else if ( class1 != env.end() ) {
     347                        // var2 unbound, add to class1
     348                        class1->vars.insert( var2->get_name() );
     349                        class1->allowWidening = widen1;
     350                } else if ( class2 != env.end() ) {
     351                        // var1 unbound, add to class2
     352                        class2->vars.insert( var1->get_name() );
     353                        class2->allowWidening = widen2;
     354                } else {
     355                        // neither var bound, create new class
     356                        EqvClass newClass;
     357                        newClass.vars.insert( var1->get_name() );
     358                        newClass.vars.insert( var2->get_name() );
     359                        newClass.allowWidening = widen1 && widen2;
     360                        newClass.data = data;
     361                        env.push_back( std::move(newClass) );
     362                } // if
     363                return true;
     364        }
     365
     366        void TypeEnvironment::forbidWidening() {
     367                for ( EqvClass& c : env ) c.allowWidening = false;
     368        }
     369
    214370        std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) {
    215371                env.print( out );
Note: See TracChangeset for help on using the changeset viewer.