Ignore:
Timestamp:
Oct 29, 2019, 4:01:24 PM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
773db65, 9421f3d8
Parents:
7951100 (diff), 8364209 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/TypeEnvironment.cc

    r7951100 rb067d9b  
    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 : Andrew Beach
     12// Last Modified On : Fri Jun 18 14:27:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    1717#include <algorithm>                   // for copy, set_intersection
    1818#include <iterator>                    // for ostream_iterator, insert_iterator
     19#include <memory>                      // for unique_ptr
    1920#include <utility>                     // for pair, move
    2021
     
    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 {
     
    6569        }
    6670
     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;
     75        }
     76
    6777        EqvClass &EqvClass::operator=( const EqvClass &other ) {
    6878                if ( this == &other ) return *this;
     
    7282        }
    7383
     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
    7497        EqvClass::~EqvClass() {
    7598                delete type;
     99        }
     100
     101        void EqvClass::set_type( Type* ty ) {
     102                if ( ty == type ) return;
     103                delete type;
     104                type = ty;
    76105        }
    77106
     
    91120
    92121        const EqvClass* TypeEnvironment::lookup( const std::string &var ) const {
    93                 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) {
    94                         if ( i->vars.find( var ) != i->vars.end() ) {
    95 ///       std::cout << var << " is in class ";
    96 ///       i->print( std::cout );
    97                                 return &*i;
    98                         }
    99 ///     std::cout << var << " is not in class ";
    100 ///     i->print( std::cout );
     122                for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) {
     123                        if ( i->vars.find( var ) != i->vars.end() ) return &*i;
    101124                } // for
    102125                return nullptr;
     
    109132                        ++next;
    110133                        std::set<std::string> intersection;
    111                         std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 
     134                        std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(),
    112135                                std::inserter( intersection, intersection.begin() ) );
    113136                        if ( ! intersection.empty() ) { env.erase( i ); }
    114137                        i = next;
    115138                }
    116         }
    117 
    118         void TypeEnvironment::add( const EqvClass &eqvClass ) {
    119                 filterOverlappingClasses( env, eqvClass );
    120                 env.push_back( eqvClass );
    121139        }
    122140
     
    131149                        newClass.vars.insert( (*i)->get_name() );
    132150                        newClass.data = TypeDecl::Data{ (*i) };
    133                         env.push_back( newClass );
     151                        env.push_back( std::move(newClass) );
    134152                } // for
    135153        }
     
    145163                        // transition to TypeSubstitution
    146164                        newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false };
    147                         add( newClass );
     165                        add( std::move(newClass) );
    148166                }
    149167        }
    150168
    151169        void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const {
    152                 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
     170                for ( ClassList::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
    153171                        for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) {
    154 ///       std::cerr << "adding " << *theVar;
    155172                                if ( theClass->type ) {
    156 ///         std::cerr << " bound to ";
    157 ///         theClass->type->print( std::cerr );
    158 ///         std::cerr << std::endl;
    159173                                        sub.add( *theVar, theClass->type );
    160174                                } else if ( theVar != theClass->vars.begin() ) {
    161175                                        TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype );
    162 ///         std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl;
    163176                                        sub.add( *theVar, newTypeInst );
    164177                                        delete newTypeInst;
     
    166179                        } // for
    167180                } // for
    168 ///   std::cerr << "input env is:" << std::endl;
    169 ///   print( std::cerr, 8 );
    170 ///   std::cerr << "sub is:" << std::endl;
    171 ///   sub.print( std::cerr, 8 );
    172181                sub.normalize();
    173182        }
     
    179188        }
    180189
    181         std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
    182                 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) {
    183                         if ( i->vars.find( var ) == i->vars.end() ) {
    184                                 return i;
    185                         } // if
     190        TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
     191                for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) {
     192                        if ( i->vars.count( var ) ) return i;
    186193                } // for
    187194                return env.end();
     
    192199        }
    193200
    194         void TypeEnvironment::combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) ) {
    195                 TypeEnvironment secondCopy( second );
    196                 for ( std::list< EqvClass >::iterator firstClass = env.begin(); firstClass != env.end(); ++firstClass ) {
    197                         EqvClass &newClass = *firstClass;
    198                         std::set< std::string > newVars;
    199                         for ( std::set< std::string >::const_iterator var = firstClass->vars.begin(); var != firstClass->vars.end(); ++var ) {
    200                                 std::list< EqvClass >::iterator secondClass = secondCopy.internal_lookup( *var );
    201                                 if ( secondClass != secondCopy.env.end() ) {
    202                                         newVars.insert( secondClass->vars.begin(), secondClass->vars.end() );
    203                                         if ( secondClass->type ) {
    204                                                 if ( newClass.type ) {
    205                                                         Type *newType = combineFunc( newClass.type, secondClass->type );
    206                                                         delete newClass.type;
    207                                                         newClass.type = newType;
    208                                                         newClass.allowWidening = newClass.allowWidening && secondClass->allowWidening;
    209                                                 } else {
    210                                                         newClass.type = secondClass->type->clone();
    211                                                         newClass.allowWidening = secondClass->allowWidening;
    212                                                 } // if
    213                                         } // if
    214                                         secondCopy.env.erase( secondClass );
    215                                 } // if
    216                         } // for
    217                         newClass.vars.insert( newVars.begin(), newVars.end() );
    218                 } // for
    219                 for ( std::list< EqvClass >::iterator secondClass = secondCopy.env.begin(); secondClass != secondCopy.env.end(); ++secondClass ) {
    220                         env.push_back( *secondClass );
    221                 } // for
     201        // xxx -- this should maybe be worrying about iterator invalidation (see resolv-proto)
     202        bool TypeEnvironment::mergeBound( EqvClass& to, const EqvClass& from, OpenVarSet& openVars, const SymTab::Indexer& indexer ) {
     203                if ( from.type ) {
     204                        if ( to.type ) {
     205                                // attempt to unify bound types
     206                                std::unique_ptr<Type> toType{ to.type->clone() }, fromType{ from.type->clone() };
     207                                WidenMode widen{ to.allowWidening, from.allowWidening };
     208                                Type* common = nullptr;
     209                                AssertionSet need, have;
     210                                if ( unifyInexact( toType.get(), fromType.get(), *this, need, have, openVars, widen, indexer, common ) ) {
     211                                        // unifies, set common type if necessary
     212                                        if ( common ) {
     213                                                common->get_qualifiers() = Type::Qualifiers{};
     214                                                to.set_type( common );
     215                                        }
     216                                } else return false; // cannot unify
     217                        } else {
     218                                to.type = from.type->clone();
     219                        }
     220                }
     221
     222                // unify widening if matches
     223                to.allowWidening &= from.allowWidening;
     224                return true;
     225        }
     226
     227        // xxx -- this should maybe be worrying about iterator invalidation (see resolv-proto)
     228        bool TypeEnvironment::mergeClasses( TypeEnvironment::ClassList::iterator to, TypeEnvironment::ClassList::iterator from, OpenVarSet& openVars, const SymTab::Indexer& indexer ) {
     229                EqvClass& r = *to;
     230                EqvClass& s = *from;
     231
     232                // ensure bounds match
     233                if ( ! mergeBound( r, s, openVars, indexer ) ) return false;
     234
     235                // check safely bindable
     236                if ( r.type && occursIn( r.type, s.vars.begin(), s.vars.end(), *this ) ) return false;
     237               
     238                // merge classes in
     239                r.vars.insert( s.vars.begin(), s.vars.end() );
     240                r.allowWidening &= s.allowWidening;
     241                env.erase( from );
     242
     243                return true;
     244        }
     245
     246        bool TypeEnvironment::combine( const TypeEnvironment& o, OpenVarSet& openVars, const SymTab::Indexer& indexer ) {
     247                // short-circuit easy cases
     248                if ( o.isEmpty() ) return true;
     249                if ( isEmpty() ) {
     250                        simpleCombine( o );
     251                        return true;
     252                }
     253
     254                // merge classes
     255                for ( auto ct = o.env.begin(); ct != o.env.end(); ++ct ) {
     256                        const EqvClass& c = *ct;
     257
     258                        // typeclass in local environment bound to c
     259                        auto rt = env.end();
     260
     261                        // look for first existing bound variable
     262                        auto vt = c.vars.begin();
     263                        for ( ; vt != c.vars.end(); ++vt ) {
     264                                rt = internal_lookup( *vt );
     265                                if ( rt != env.end() ) break;
     266                        }
     267
     268                        if ( rt != env.end() ) {  // c needs to be merged into *rt
     269                                EqvClass& r = *rt;
     270                                // merge bindings
     271                                if ( ! mergeBound( r, c, openVars, indexer ) ) return false;
     272                                // merge previous unbound variables into this class, checking occurs if needed
     273                                if ( r.type ) for ( auto ut = c.vars.begin(); ut != vt; ++ut ) {
     274                                        if ( occurs( r.type, *ut, *this ) ) return false;
     275                                        r.vars.insert( *ut );
     276                                } else { r.vars.insert( c.vars.begin(), vt ); }
     277                                // merge subsequent variables into this class (skipping *vt, already there)
     278                                while ( ++vt != c.vars.end() ) {
     279                                        auto st = internal_lookup( *vt );
     280                                        if ( st == env.end() ) {
     281                                                // unbound, safe to add if passes occurs
     282                                                if ( r.type && occurs( r.type, *vt, *this ) ) return false;
     283                                                r.vars.insert( *vt );
     284                                        } else if ( st != rt ) {
     285                                                // bound, but not to the same class
     286                                                if ( ! mergeClasses( rt, st, openVars, indexer ) ) return false;
     287                                        }   // ignore bound into the same class
     288                                }
     289                        } else {  // no variables in c bound; just copy up
     290                                env.push_back( c );
     291                        }
     292                }
     293
     294                // merged all classes
     295                return true;
    222296        }
    223297
    224298        void TypeEnvironment::extractOpenVars( OpenVarSet &openVars ) const {
    225                 for ( std::list< EqvClass >::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) {
     299                for ( ClassList::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) {
    226300                        for ( std::set< std::string >::const_iterator var = eqvClass->vars.begin(); var != eqvClass->vars.end(); ++var ) {
    227301                                openVars[ *var ] = eqvClass->data;
     
    241315        }
    242316
     317        bool isFtype( const Type * type ) {
     318                if ( dynamic_cast< const FunctionType * >( type ) ) {
     319                        return true;
     320                } else if ( const TypeInstType *typeInst = dynamic_cast< const TypeInstType * >( type ) ) {
     321                        return typeInst->get_isFtype();
     322                } // if
     323                return false;
     324        }
     325
     326        bool tyVarCompatible( const TypeDecl::Data & data, const Type * type ) {
     327                switch ( data.kind ) {
     328                  case TypeDecl::Dtype:
     329                        // to bind to an object type variable, the type must not be a function type.
     330                        // if the type variable is specified to be a complete type then the incoming
     331                        // type must also be complete
     332                        // xxx - should this also check that type is not a tuple type and that it's not a ttype?
     333                        return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
     334                  case TypeDecl::Ftype:
     335                        return isFtype( type );
     336                  case TypeDecl::Ttype:
     337                        // ttype unifies with any tuple type
     338                        return dynamic_cast< const TupleType * >( type ) || Tuples::isTtype( type );
     339                  default:
     340                        assertf(false, "Unhandled tyvar kind: %d", data.kind);
     341                } // switch
     342                return false;
     343        }
     344
     345        bool TypeEnvironment::bindVar( const TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
     346
     347                // remove references from other, so that type variables can only bind to value types
     348                bindTo = bindTo->stripReferences();
     349                OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
     350                assert( tyvar != openVars.end() );
     351                if ( ! tyVarCompatible( tyvar->second, bindTo ) ) {
     352                        return false;
     353                } // if
     354                if ( occurs( bindTo, typeInst->get_name(), *this ) ) {
     355                        return false;
     356                } // if
     357                auto curClass = internal_lookup( typeInst->get_name() );
     358                if ( curClass != env.end() ) {
     359                        if ( curClass->type ) {
     360                                Type *common = 0;
     361                                // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to
     362                                std::unique_ptr< Type > newType( curClass->type->clone() );
     363                                newType->tq = typeInst->tq;
     364                                if ( unifyInexact( newType.get(), bindTo, *this, need, have, openVars, widen & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {
     365                                        if ( common ) {
     366                                                common->get_qualifiers() = Type::Qualifiers{};
     367                                                curClass->set_type( common );
     368                                        } // if
     369                                } else return false;
     370                        } else {
     371                                Type* newType = bindTo->clone();
     372                                newType->get_qualifiers() = Type::Qualifiers{};
     373                                curClass->set_type( newType );
     374                                curClass->allowWidening = widen.first && widen.second;
     375                        } // if
     376                } else {
     377                        EqvClass newClass;
     378                        newClass.vars.insert( typeInst->get_name() );
     379                        newClass.type = bindTo->clone();
     380                        newClass.type->get_qualifiers() = Type::Qualifiers();
     381                        newClass.allowWidening = widen.first && widen.second;
     382                        newClass.data = data;
     383                        env.push_back( std::move(newClass) );
     384                } // if
     385                return true;
     386        }
     387
     388        bool TypeEnvironment::bindVarToVar( const TypeInstType * var1, const TypeInstType * var2,
     389                        TypeDecl::Data && data, AssertionSet &need, AssertionSet &have,
     390                        const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
     391
     392                auto class1 = internal_lookup( var1->get_name() );
     393                auto class2 = internal_lookup( var2->get_name() );
     394
     395                // exit early if variables already bound together
     396                if ( class1 != env.end() && class1 == class2 ) {
     397                        class1->allowWidening &= widen;
     398                        return true;
     399                }
     400
     401                bool widen1 = false, widen2 = false;
     402                const Type *type1 = nullptr, *type2 = nullptr;
     403
     404                // check for existing bindings, perform occurs check
     405                if ( class1 != env.end() ) {
     406                        if ( class1->type ) {
     407                                if ( occurs( class1->type, var2->get_name(), *this ) ) return false;
     408                                type1 = class1->type;
     409                        } // if
     410                        widen1 = widen.first && class1->allowWidening;
     411                } // if
     412                if ( class2 != env.end() ) {
     413                        if ( class2->type ) {
     414                                if ( occurs( class2->type, var1->get_name(), *this ) ) return false;
     415                                type2 = class2->type;
     416                        } // if
     417                        widen2 = widen.second && class2->allowWidening;
     418                } // if
     419
     420                if ( type1 && type2 ) {
     421                        // both classes bound, merge if bound types can be unified
     422                        std::unique_ptr<Type> newType1{ type1->clone() }, newType2{ type2->clone() };
     423                        WidenMode newWidenMode{ widen1, widen2 };
     424                        Type *common = 0;
     425                        if ( unifyInexact( newType1.get(), newType2.get(), *this, need, have, openVars, newWidenMode, indexer, common ) ) {
     426                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
     427                                class1->allowWidening = widen1 && widen2;
     428                                if ( common ) {
     429                                        common->get_qualifiers() = Type::Qualifiers{};
     430                                        class1->set_type( common );
     431                                }
     432                                class1->data.isComplete |= data.isComplete;
     433                                env.erase( class2 );
     434                        } else return false;
     435                } else if ( class1 != env.end() && class2 != env.end() ) {
     436                        // both classes exist, at least one unbound, merge unconditionally
     437                        if ( type1 ) {
     438                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
     439                                class1->allowWidening = widen1;
     440                                class1->data.isComplete |= data.isComplete;
     441                                env.erase( class2 );
     442                        } else {
     443                                class2->vars.insert( class1->vars.begin(), class1->vars.end() );
     444                                class2->allowWidening = widen2;
     445                                class2->data.isComplete |= data.isComplete;
     446                                env.erase( class1 );
     447                        } // if
     448                } else if ( class1 != env.end() ) {
     449                        // var2 unbound, add to class1
     450                        class1->vars.insert( var2->get_name() );
     451                        class1->allowWidening = widen1;
     452                        class1->data.isComplete |= data.isComplete;
     453                } else if ( class2 != env.end() ) {
     454                        // var1 unbound, add to class2
     455                        class2->vars.insert( var1->get_name() );
     456                        class2->allowWidening = widen2;
     457                        class2->data.isComplete |= data.isComplete;
     458                } else {
     459                        // neither var bound, create new class
     460                        EqvClass newClass;
     461                        newClass.vars.insert( var1->get_name() );
     462                        newClass.vars.insert( var2->get_name() );
     463                        newClass.allowWidening = widen1 && widen2;
     464                        newClass.data = data;
     465                        env.push_back( std::move(newClass) );
     466                } // if
     467                return true;
     468        }
     469
     470        void TypeEnvironment::forbidWidening() {
     471                for ( EqvClass& c : env ) c.allowWidening = false;
     472        }
     473
    243474        std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) {
    244475                env.print( out );
Note: See TracChangeset for help on using the changeset viewer.