Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/Unify.cc

    ra2a77af r6c3a988f  
    2626#include "SymTab/Indexer.h"
    2727#include "Common/utility.h"
    28 
     28#include "Tuples/Tuples.h"
    2929
    3030// #define DEBUG
     
    9999                newFirst->get_qualifiers() = Type::Qualifiers();
    100100                newSecond->get_qualifiers() = Type::Qualifiers();
    101 ///   std::cout << "first is ";
    102 ///   first->print( std::cout );
    103 ///   std::cout << std::endl << "second is ";
    104 ///   second->print( std::cout );
    105 ///   std::cout << std::endl << "newFirst is ";
    106 ///   newFirst->print( std::cout );
    107 ///   std::cout << std::endl << "newSecond is ";
    108 ///   newSecond->print( std::cout );
    109 ///   std::cout << std::endl;
     101///   std::cerr << "first is ";
     102///   first->print( std::cerr );
     103///   std::cerr << std::endl << "second is ";
     104///   second->print( std::cerr );
     105///   std::cerr << std::endl << "newFirst is ";
     106///   newFirst->print( std::cerr );
     107///   std::cerr << std::endl << "newSecond is ";
     108///   newSecond->print( std::cerr );
     109///   std::cerr << std::endl;
    110110                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    111111                delete newFirst;
     
    123123        }
    124124
    125         bool tyVarCompatible( TypeDecl::Kind kind, Type *type, const SymTab::Indexer &indexer ) {
    126                 switch ( kind ) {
     125        struct CompleteTypeChecker : public Visitor {
     126                virtual void visit( VoidType *basicType ) { status = false; }
     127                virtual void visit( BasicType *basicType ) {}
     128                virtual void visit( PointerType *pointerType ) {}
     129                virtual void visit( ArrayType *arrayType ) { status = ! arrayType->get_isVarLen(); }
     130                virtual void visit( FunctionType *functionType ) {}
     131                virtual void visit( StructInstType *aggregateUseType ) { status = aggregateUseType->get_baseStruct()->has_body(); }
     132                virtual void visit( UnionInstType *aggregateUseType ) { status = aggregateUseType->get_baseUnion()->has_body(); }
     133                // xxx - enum inst does not currently contain a pointer to base, this should be fixed.
     134                virtual void visit( EnumInstType *aggregateUseType ) { /* status = aggregateUseType->get_baseEnum()->hasBody(); */ }
     135                virtual void visit( TraitInstType *aggregateUseType ) { assert( false ); }
     136                virtual void visit( TypeInstType *aggregateUseType ) { status = aggregateUseType->get_baseType()->isComplete(); }
     137                virtual void visit( TupleType *tupleType ) {} // xxx - not sure if this is right, might need to recursively check complete-ness
     138                virtual void visit( TypeofType *typeofType ) { assert( false ); }
     139                virtual void visit( AttrType *attrType ) { assert( false ); } // xxx - not sure what to do here
     140                virtual void visit( VarArgsType *varArgsType ){} // xxx - is this right?
     141                virtual void visit( ZeroType *zeroType ) {}
     142                virtual void visit( OneType *oneType ) {}
     143                bool status = true;
     144        };
     145        bool isComplete( Type * type ) {
     146                CompleteTypeChecker checker;
     147                assert( type );
     148                type->accept( checker );
     149                return checker.status;
     150        }
     151
     152        bool tyVarCompatible( const TypeDecl::Data & data, Type *type, const SymTab::Indexer &indexer ) {
     153                switch ( data.kind ) {
    127154                  case TypeDecl::Any:
    128155                  case TypeDecl::Dtype:
    129                         return ! isFtype( type, indexer );
    130 
     156                        // to bind to an object type variable, the type must not be a function type.
     157                        // if the type variable is specified to be a complete type then the incoming
     158                        // 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?
     160                        return ! isFtype( type, indexer ) && (! data.isComplete || isComplete( type ));
    131161                  case TypeDecl::Ftype:
    132162                        return isFtype( type, indexer );
     163                        case TypeDecl::Ttype:
     164                        // ttype unifies with any tuple type
     165                        return dynamic_cast< TupleType * >( type );
    133166                } // switch
    134                 assert( false );
    135167                return false;
    136168        }
    137169
    138         bool bindVar( TypeInstType *typeInst, Type *other, TypeDecl::Kind kind, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     170        bool bindVar( TypeInstType *typeInst, Type *other, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    139171                OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
    140172                assert( tyvar != openVars.end() );
     
    175207                        newClass.type->get_qualifiers() = Type::Qualifiers();
    176208                        newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
    177                         newClass.kind = kind;
     209                        newClass.data = data;
    178210                        env.add( newClass );
    179211                } // if
     
    181213        }
    182214
    183         bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, TypeDecl::Kind kind, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     215        bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    184216                bool result = true;
    185217                EqvClass class1, class2;
     
    210242
    211243                if ( type1 && type2 ) {
    212 //    std::cout << "has type1 && type2" << std::endl;
     244//    std::cerr << "has type1 && type2" << std::endl;
    213245                        WidenMode newWidenMode ( widen1, widen2 );
    214246                        Type *common = 0;
     
    248280                        newClass.vars.insert( var2->get_name() );
    249281                        newClass.allowWidening = widen1 && widen2;
    250                         newClass.kind = kind;
     282                        newClass.data = data;
    251283                        env.add( newClass );
    252284                } // if
     
    311343                } // if
    312344#ifdef DEBUG
    313                 std::cout << "============ unifyExact" << std::endl;
    314                 std::cout << "type1 is ";
    315                 type1->print( std::cout );
    316                 std::cout << std::endl << "type2 is ";
    317                 type2->print( std::cout );
    318                 std::cout << std::endl << "openVars are ";
    319                 printOpenVarSet( openVars, std::cout, 8 );
    320                 std::cout << std::endl << "input env is " << std::endl;
    321                 debugEnv.print( std::cout, 8 );
    322                 std::cout << std::endl << "result env is " << std::endl;
    323                 env.print( std::cout, 8 );
    324                 std::cout << "result is " << result << std::endl;
     345                std::cerr << "============ unifyExact" << std::endl;
     346                std::cerr << "type1 is ";
     347                type1->print( std::cerr );
     348                std::cerr << std::endl << "type2 is ";
     349                type2->print( std::cerr );
     350                std::cerr << std::endl << "openVars are ";
     351                printOpenVarSet( openVars, std::cerr, 8 );
     352                std::cerr << std::endl << "input env is " << std::endl;
     353                debugEnv.print( std::cerr, 8 );
     354                std::cerr << std::endl << "result env is " << std::endl;
     355                env.print( std::cerr, 8 );
     356                std::cerr << "result is " << result << std::endl;
    325357#endif
    326358                return result;
     
    337369                bool result;
    338370#ifdef DEBUG
    339                 std::cout << "unifyInexact type 1 is ";
    340                 type1->print( std::cout );
    341                 std::cout << "type 2 is ";
    342                 type2->print( std::cout );
    343                 std::cout << std::endl;
     371                std::cerr << "unifyInexact type 1 is ";
     372                type1->print( std::cerr );
     373                std::cerr << "type 2 is ";
     374                type2->print( std::cerr );
     375                std::cerr << std::endl;
    344376#endif
    345377                if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer ) ) {
    346378#ifdef DEBUG
    347                         std::cout << "unifyInexact: no exact unification found" << std::endl;
     379                        std::cerr << "unifyInexact: no exact unification found" << std::endl;
    348380#endif
    349381                        if ( ( common = commonType( type1, type2, widenMode.widenFirst, widenMode.widenSecond, indexer, env, openVars ) ) ) {
    350382                                common->get_qualifiers() = tq1 + tq2;
    351383#ifdef DEBUG
    352                                 std::cout << "unifyInexact: common type is ";
    353                                 common->print( std::cout );
    354                                 std::cout << std::endl;
     384                                std::cerr << "unifyInexact: common type is ";
     385                                common->print( std::cerr );
     386                                std::cerr << std::endl;
    355387#endif
    356388                                result = true;
    357389                        } else {
    358390#ifdef DEBUG
    359                                 std::cout << "unifyInexact: no common type found" << std::endl;
     391                                std::cerr << "unifyInexact: no common type found" << std::endl;
    360392#endif
    361393                                result = false;
     
    394426
    395427        void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
    396 ///   std::cout << "assertion set is" << std::endl;
    397 ///   printAssertionSet( assertions, std::cout, 8 );
    398 ///   std::cout << "looking for ";
    399 ///   assert->print( std::cout );
    400 ///   std::cout << std::endl;
     428///   std::cerr << "assertion set is" << std::endl;
     429///   printAssertionSet( assertions, std::cerr, 8 );
     430///   std::cerr << "looking for ";
     431///   assert->print( std::cerr );
     432///   std::cerr << std::endl;
    401433                AssertionSet::iterator i = assertions.find( assert );
    402434                if ( i != assertions.end() ) {
    403 ///     std::cout << "found it!" << std::endl;
    404                         i->second = true;
     435///     std::cerr << "found it!" << std::endl;
     436                        i->second.isUsed = true;
    405437                } // if
    406438        }
     
    456488        }
    457489
     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
    458500        template< typename Iterator1, typename Iterator2 >
    459501        bool unifyDeclList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    460502                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    461                         // Type * commonType;
    462                         // if ( ! unifyInexact( (*list1Begin)->get_type(), (*list2Begin)->get_type(), env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {
    463                         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 ) ) {
    464516                                return false;
    465517                        } // if
    466518                } // for
    467                 if ( list1Begin != list1End || list2Begin != list2End ) {
    468                         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;
    469532                } else {
    470533                        return true;
    471534                } // 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                }
    472573        }
    473574
     
    475576                FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
    476577                if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
    477                         if ( functionType->get_parameters().size() == otherFunction->get_parameters().size() && functionType->get_returnVals().size() == otherFunction->get_returnVals().size() ) {
    478                                 if ( unifyDeclList( functionType->get_parameters().begin(), functionType->get_parameters().end(), otherFunction->get_parameters().begin(), otherFunction->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    479                                         if ( unifyDeclList( functionType->get_returnVals().begin(), functionType->get_returnVals().end(), otherFunction->get_returnVals().begin(), otherFunction->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    480 
     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
    481591                                                markAssertions( haveAssertions, needAssertions, functionType );
    482592                                                markAssertions( haveAssertions, needAssertions, otherFunction );
Note: See TracChangeset for help on using the changeset viewer.