Ignore:
Timestamp:
Jan 11, 2017, 4:11:02 PM (9 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
075734f
Parents:
bb82c03 (diff), d3a85240 (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/Unify.cc

    rbb82c03 r2162c2c  
    2626#include "SymTab/Indexer.h"
    2727#include "Common/utility.h"
    28 
     28#include "Tuples/Tuples.h"
    2929
    3030// #define DEBUG
     
    157157                        // if the type variable is specified to be a complete type then the incoming
    158158                        // type must also be complete
     159                        // xxx - should this also check that type is not a tuple type and that it's not a ttype?
    159160                        return ! isFtype( type, indexer ) && (! data.isComplete || isComplete( type ));
    160161                  case TypeDecl::Ftype:
    161162                        return isFtype( type, indexer );
     163                        case TypeDecl::Ttype:
     164                        // ttype unifies with any tuple type
     165                        return dynamic_cast< TupleType * >( type );
    162166                } // switch
    163                 assert( false );
    164167                return false;
    165168        }
     
    431434                if ( i != assertions.end() ) {
    432435///     std::cerr << "found it!" << std::endl;
    433                         i->second = true;
     436                        i->second.isUsed = true;
    434437                } // if
    435438        }
     
    485488        }
    486489
     490        template< typename Iterator >
     491        std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end ) {
     492                std::list< Type * > types;
     493                for ( ; begin != end; ++begin ) {
     494                        // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple
     495                        flatten( (*begin)->get_type(), back_inserter( types ) );
     496                }
     497                return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );
     498        }
     499
    487500        template< typename Iterator1, typename Iterator2 >
    488501        bool unifyDeclList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    489502                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    490                         // Type * commonType;
    491                         // if ( ! unifyInexact( (*list1Begin)->get_type(), (*list2Begin)->get_type(), env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {
    492                         if ( ! unifyExact( (*list1Begin)->get_type(), (*list2Begin)->get_type(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
     503                        Type * t1 = (*list1Begin)->get_type();
     504                        Type * t2 = (*list2Begin)->get_type();
     505                        bool isTtype1 = Tuples::isTtype( t1 );
     506                        bool isTtype2 = Tuples::isTtype( t2 );
     507                        // xxx - assumes ttype must be last parameter
     508                        // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
     509                        if ( isTtype1 && ! isTtype2 ) {
     510                                // combine all of the things in list2, then unify
     511                                return unifyExact( t1, combineTypes( list2Begin, list2End ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     512                        } else if ( isTtype2 && ! isTtype1 ) {
     513                                // combine all of the things in list1, then unify
     514                                return unifyExact( combineTypes( list1Begin, list1End ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     515                        } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
    493516                                return false;
    494517                        } // if
    495518                } // for
    496                 if ( list1Begin != list1End || list2Begin != list2End ) {
    497                         return false;
     519                // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype
     520                if ( list1Begin != list1End ) {
     521                        // try unifying empty tuple type with ttype
     522                        Type * t1 = (*list1Begin)->get_type();
     523                        if ( Tuples::isTtype( t1 ) ) {
     524                                return unifyExact( t1, combineTypes( list2Begin, list2End ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     525                        } else return false;
     526                } else if ( list2Begin != list2End ) {
     527                        // try unifying empty tuple type with ttype
     528                        Type * t2 = (*list2Begin)->get_type();
     529                        if ( Tuples::isTtype( t2 ) ) {
     530                                return unifyExact( combineTypes( list1Begin, list1End ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     531                        } else return false;
    498532                } else {
    499533                        return true;
    500534                } // if
     535        }
     536
     537        /// Finds ttypes and replaces them with their expansion, if known.
     538        /// This needs to be done so that satisfying ttype assertions is easier.
     539        /// If this isn't done then argument lists can have wildly different
     540        /// size and structure, when they should be compatible.
     541        struct TtypeExpander : public Mutator {
     542                TypeEnvironment & env;
     543                TtypeExpander( TypeEnvironment & env ) : env( env ) {}
     544                Type * mutate( TypeInstType * typeInst ) {
     545                        EqvClass eqvClass;
     546                        if ( env.lookup( typeInst->get_name(), eqvClass ) ) {
     547                                if ( eqvClass.data.kind == TypeDecl::Ttype ) {
     548                                        // expand ttype parameter into its actual type
     549                                        if ( eqvClass.type ) {
     550                                                delete typeInst;
     551                                                return eqvClass.type->clone();
     552                                        }
     553                                }
     554                        }
     555                        return typeInst;
     556                }
     557        };
     558
     559        /// flattens a list of declarations, so that each tuple type has a single declaration.
     560        /// makes use of TtypeExpander to ensure ttypes are flat as well.
     561        void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {
     562                dst.clear();
     563                for ( DeclarationWithType * dcl : src ) {
     564                        TtypeExpander expander( env );
     565                        dcl->acceptMutator( expander );
     566                        std::list< Type * > types;
     567                        flatten( dcl->get_type(), back_inserter( types ) );
     568                        for ( Type * t : types ) {
     569                                dst.push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, t, nullptr ) );
     570                        }
     571                        delete dcl;
     572                }
    501573        }
    502574
     
    504576                FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
    505577                if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
    506                         if ( functionType->get_parameters().size() == otherFunction->get_parameters().size() && functionType->get_returnVals().size() == otherFunction->get_returnVals().size() ) {
    507                                 if ( unifyDeclList( functionType->get_parameters().begin(), functionType->get_parameters().end(), otherFunction->get_parameters().begin(), otherFunction->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    508                                         if ( unifyDeclList( functionType->get_returnVals().begin(), functionType->get_returnVals().end(), otherFunction->get_returnVals().begin(), otherFunction->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    509 
     578                        // flatten the parameter lists for both functions so that tuple structure
     579                        // doesn't affect unification. Must be a clone so that the types don't change.
     580                        std::unique_ptr<FunctionType> flatFunc( functionType->clone() );
     581                        std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );
     582                        flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );
     583                        flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );
     584
     585                        // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
     586                        if ( (flatFunc->get_parameters().size() == flatOther->get_parameters().size() && flatFunc->get_returnVals().size() == flatOther->get_returnVals().size()) || flatFunc->isTtype() || flatOther->isTtype() ) {
     587                                if ( unifyDeclList( flatFunc->get_parameters().begin(), flatFunc->get_parameters().end(), flatOther->get_parameters().begin(), flatOther->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     588                                        if ( unifyDeclList( flatFunc->get_returnVals().begin(), flatFunc->get_returnVals().end(), flatOther->get_returnVals().begin(), flatOther->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     589
     590                                                // the original types must be used in mark assertions, since pointer comparisons are used
    510591                                                markAssertions( haveAssertions, needAssertions, functionType );
    511592                                                markAssertions( haveAssertions, needAssertions, otherFunction );
Note: See TracChangeset for help on using the changeset viewer.