Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/Unify.cc

    rc6b4432 r8f31be6  
    3333#include "AST/TypeEnvironment.hpp"
    3434#include "Common/Eval.h"            // for eval
     35#include "Common/PassVisitor.h"     // for PassVisitor
    3536#include "CommonType.hpp"           // for commonType
    3637#include "FindOpenVars.h"           // for findOpenVars
    3738#include "SpecCost.hpp"             // for SpecCost
     39#include "SynTree/LinkageSpec.h"    // for C
     40#include "SynTree/Constant.h"       // for Constant
     41#include "SynTree/Declaration.h"    // for TypeDecl, TypeDecl::Data, Declarati...
     42#include "SynTree/Expression.h"     // for TypeExpr, Expression, ConstantExpr
     43#include "SynTree/Mutator.h"        // for Mutator
     44#include "SynTree/Type.h"           // for Type, TypeInstType, FunctionType
     45#include "SynTree/Visitor.h"        // for Visitor
    3846#include "Tuples/Tuples.h"          // for isTtype
     47#include "TypeEnvironment.h"        // for EqvClass, AssertionSet, OpenVarSet
    3948#include "typeops.h"                // for flatten, occurs
    4049
     
    4352}
    4453
     54namespace SymTab {
     55        class Indexer;
     56}  // namespace SymTab
     57
    4558// #define DEBUG
    4659
    4760namespace ResolvExpr {
     61
     62// Template Helpers:
     63template< typename Iterator1, typename Iterator2 >
     64bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {
     65        for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
     66                Type *commonType = 0;
     67                if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
     68                        return false;
     69                } // if
     70                commonTypes.push_back( commonType );
     71        } // for
     72        return ( list1Begin == list1End && list2Begin == list2End );
     73}
     74
     75template< typename Iterator1, typename Iterator2 >
     76bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     77        std::list< Type* > commonTypes;
     78        if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions,  openVars, indexer, commonTypes ) ) {
     79                deleteAll( commonTypes );
     80                return true;
     81        } else {
     82                return false;
     83        } // if
     84}
     85
     86        struct Unify_old : public WithShortCircuiting {
     87                Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
     88
     89                bool get_result() const { return result; }
     90
     91                void previsit( BaseSyntaxNode * ) { visit_children = false; }
     92
     93                void postvisit( VoidType * voidType );
     94                void postvisit( BasicType * basicType );
     95                void postvisit( PointerType * pointerType );
     96                void postvisit( ArrayType * arrayType );
     97                void postvisit( ReferenceType * refType );
     98                void postvisit( FunctionType * functionType );
     99                void postvisit( StructInstType * aggregateUseType );
     100                void postvisit( UnionInstType * aggregateUseType );
     101                void postvisit( EnumInstType * aggregateUseType );
     102                void postvisit( TraitInstType * aggregateUseType );
     103                void postvisit( TypeInstType * aggregateUseType );
     104                void postvisit( TupleType * tupleType );
     105                void postvisit( VarArgsType * varArgsType );
     106                void postvisit( ZeroType * zeroType );
     107                void postvisit( OneType * oneType );
     108
     109          private:
     110                template< typename RefType > void handleRefType( RefType *inst, Type *other );
     111                template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
     112
     113                bool result;
     114                Type *type2;                            // inherited
     115                TypeEnvironment &env;
     116                AssertionSet &needAssertions;
     117                AssertionSet &haveAssertions;
     118                const OpenVarSet &openVars;
     119                WidenMode widen;
     120                const SymTab::Indexer &indexer;
     121        };
     122
     123        /// Attempts an inexact unification of type1 and type2.
     124        /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)
     125        bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
     126        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
     127
     128        bool unifyExact(
     129                const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
     130                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     131                WidenMode widen );
     132
     133        bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
     134                TypeEnvironment newEnv;
     135                OpenVarSet openVars, closedVars; // added closedVars
     136                AssertionSet needAssertions, haveAssertions;
     137                Type * newFirst = first->clone(), * newSecond = second->clone();
     138                env.apply( newFirst );
     139                env.apply( newSecond );
     140
     141                // do we need to do this? Seems like we do, types should be able to be compatible if they
     142                // have free variables that can unify
     143                findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false );
     144                findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true );
     145
     146                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     147                delete newFirst;
     148                delete newSecond;
     149                return result;
     150        }
    48151
    49152        bool typesCompatible(
     
    62165
    63166                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
     167        }
     168
     169        bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     170                TypeEnvironment newEnv;
     171                OpenVarSet openVars;
     172                AssertionSet needAssertions, haveAssertions;
     173                Type *newFirst = first->clone(), *newSecond = second->clone();
     174                env.apply( newFirst );
     175                env.apply( newSecond );
     176                newFirst->get_qualifiers() = Type::Qualifiers();
     177                newSecond->get_qualifiers() = Type::Qualifiers();
     178
     179                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     180                delete newFirst;
     181                delete newSecond;
     182                return result;
    64183        }
    65184
     
    99218                        subSecond,
    100219                        newEnv, need, have, open, noWiden() );
     220        }
     221
     222        bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     223                OpenVarSet closedVars;
     224                findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
     225                findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
     226                Type *commonType = 0;
     227                if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {
     228                        if ( commonType ) {
     229                                delete commonType;
     230                        } // if
     231                        return true;
     232                } else {
     233                        return false;
     234                } // if
     235        }
     236
     237        bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) {
     238                OpenVarSet closedVars;
     239                findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
     240                findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
     241                return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType );
     242        }
     243
     244        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
     245#ifdef DEBUG
     246                TypeEnvironment debugEnv( env );
     247#endif
     248                if ( type1->get_qualifiers() != type2->get_qualifiers() ) {
     249                        return false;
     250                }
     251
     252                bool result;
     253                TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 );
     254                TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 );
     255                OpenVarSet::const_iterator entry1, entry2;
     256                if ( var1 ) {
     257                        entry1 = openVars.find( var1->get_name() );
     258                } // if
     259                if ( var2 ) {
     260                        entry2 = openVars.find( var2->get_name() );
     261                } // if
     262                bool isopen1 = var1 && ( entry1 != openVars.end() );
     263                bool isopen2 = var2 && ( entry2 != openVars.end() );
     264
     265                if ( isopen1 && isopen2 ) {
     266                        if ( entry1->second.kind != entry2->second.kind ) {
     267                                result = false;
     268                        } else {
     269                                result = env.bindVarToVar(
     270                                        var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
     271                                        haveAssertions, openVars, widen, indexer );
     272                        }
     273                } else if ( isopen1 ) {
     274                        result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );
     275                } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?
     276                        result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );
     277                } else {
     278                        PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );
     279                        type1->accept( comparator );
     280                        result = comparator.pass.get_result();
     281                } // if
     282#ifdef DEBUG
     283                std::cerr << "============ unifyExact" << std::endl;
     284                std::cerr << "type1 is ";
     285                type1->print( std::cerr );
     286                std::cerr << std::endl << "type2 is ";
     287                type2->print( std::cerr );
     288                std::cerr << std::endl << "openVars are ";
     289                printOpenVarSet( openVars, std::cerr, 8 );
     290                std::cerr << std::endl << "input env is " << std::endl;
     291                debugEnv.print( std::cerr, 8 );
     292                std::cerr << std::endl << "result env is " << std::endl;
     293                env.print( std::cerr, 8 );
     294                std::cerr << "result is " << result << std::endl;
     295#endif
     296                return result;
     297        }
     298
     299        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     300                return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     301        }
     302
     303        bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {
     304                Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();
     305                type1->get_qualifiers() = Type::Qualifiers();
     306                type2->get_qualifiers() = Type::Qualifiers();
     307                bool result;
     308#ifdef DEBUG
     309                std::cerr << "unifyInexact type 1 is ";
     310                type1->print( std::cerr );
     311                std::cerr << " type 2 is ";
     312                type2->print( std::cerr );
     313                std::cerr << std::endl;
     314#endif
     315                if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {
     316#ifdef DEBUG
     317                        std::cerr << "unifyInexact: no exact unification found" << std::endl;
     318#endif
     319                        if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {
     320                                common->tq = tq1.unify( tq2 );
     321#ifdef DEBUG
     322                                std::cerr << "unifyInexact: common type is ";
     323                                common->print( std::cerr );
     324                                std::cerr << std::endl;
     325#endif
     326                                result = true;
     327                        } else {
     328#ifdef DEBUG
     329                                std::cerr << "unifyInexact: no common type found" << std::endl;
     330#endif
     331                                result = false;
     332                        } // if
     333                } else {
     334                        if ( tq1 != tq2 ) {
     335                                if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {
     336                                        common = type1->clone();
     337                                        common->tq = tq1.unify( tq2 );
     338                                        result = true;
     339                                } else {
     340                                        result = false;
     341                                } // if
     342                        } else {
     343                                common = type1->clone();
     344                                common->tq = tq1.unify( tq2 );
     345                                result = true;
     346                        } // if
     347                } // if
     348                type1->get_qualifiers() = tq1;
     349                type2->get_qualifiers() = tq2;
     350                return result;
     351        }
     352
     353        Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )
     354                : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {
     355        }
     356
     357        void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {
     358                result = dynamic_cast< VoidType* >( type2 );
     359        }
     360
     361        void Unify_old::postvisit(BasicType *basicType) {
     362                if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
     363                        result = basicType->get_kind() == otherBasic->get_kind();
     364                } // if
     365        }
     366
     367        void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
     368                AssertionSet::iterator i = assertions.find( assert );
     369                if ( i != assertions.end() ) {
     370                        i->second.isUsed = true;
     371                } // if
     372        }
     373
     374        void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) {
     375                for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
     376                        for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
     377                                markAssertionSet( assertion1, *assert );
     378                                markAssertionSet( assertion2, *assert );
     379                        } // for
     380                } // for
     381        }
     382
     383        void Unify_old::postvisit(PointerType *pointerType) {
     384                if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
     385                        result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     386                        markAssertions( haveAssertions, needAssertions, pointerType );
     387                        markAssertions( haveAssertions, needAssertions, otherPointer );
     388                } // if
     389        }
     390
     391        void Unify_old::postvisit(ReferenceType *refType) {
     392                if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
     393                        result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     394                        markAssertions( haveAssertions, needAssertions, refType );
     395                        markAssertions( haveAssertions, needAssertions, otherRef );
     396                } // if
     397        }
     398
     399        void Unify_old::postvisit(ArrayType *arrayType) {
     400                ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
     401                // to unify, array types must both be VLA or both not VLA
     402                // and must both have a dimension expression or not have a dimension
     403                if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {
     404
     405                        if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&
     406                                arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {
     407                                ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() );
     408                                ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() );
     409                                // see C11 Reference Manual 6.7.6.2.6
     410                                // two array types with size specifiers that are integer constant expressions are
     411                                // compatible if both size specifiers have the same constant value
     412                                if ( ce1 && ce2 ) {
     413                                        Constant * c1 = ce1->get_constant();
     414                                        Constant * c2 = ce2->get_constant();
     415
     416                                        if ( c1->get_value() != c2->get_value() ) {
     417                                                // does not unify if the dimension is different
     418                                                return;
     419                                        }
     420                                }
     421                        }
     422
     423                        result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     424                } // if
     425        }
     426
     427        template< typename Iterator, typename Func >
     428        std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {
     429                std::list< Type * > types;
     430                for ( ; begin != end; ++begin ) {
     431                        // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple
     432                        flatten( toType( *begin ), back_inserter( types ) );
     433                }
     434                return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );
     435        }
     436
     437        template< typename Iterator1, typename Iterator2 >
     438        bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     439                auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };
     440                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
     441                        Type * t1 = (*list1Begin)->get_type();
     442                        Type * t2 = (*list2Begin)->get_type();
     443                        bool isTtype1 = Tuples::isTtype( t1 );
     444                        bool isTtype2 = Tuples::isTtype( t2 );
     445                        // xxx - assumes ttype must be last parameter
     446                        // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
     447                        if ( isTtype1 && ! isTtype2 ) {
     448                                // combine all of the things in list2, then unify
     449                                return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     450                        } else if ( isTtype2 && ! isTtype1 ) {
     451                                // combine all of the things in list1, then unify
     452                                return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     453                        } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
     454                                return false;
     455                        } // if
     456                } // for
     457                // 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
     458                if ( list1Begin != list1End ) {
     459                        // try unifying empty tuple type with ttype
     460                        Type * t1 = (*list1Begin)->get_type();
     461                        if ( Tuples::isTtype( t1 ) ) {
     462                                return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     463                        } else return false;
     464                } else if ( list2Begin != list2End ) {
     465                        // try unifying empty tuple type with ttype
     466                        Type * t2 = (*list2Begin)->get_type();
     467                        if ( Tuples::isTtype( t2 ) ) {
     468                                return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     469                        } else return false;
     470                } else {
     471                        return true;
     472                } // if
     473        }
     474
     475        /// Finds ttypes and replaces them with their expansion, if known.
     476        /// This needs to be done so that satisfying ttype assertions is easier.
     477        /// If this isn't done then argument lists can have wildly different
     478        /// size and structure, when they should be compatible.
     479        struct TtypeExpander_old : public WithShortCircuiting {
     480                TypeEnvironment & tenv;
     481                TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}
     482                void premutate( TypeInstType * ) { visit_children = false; }
     483                Type * postmutate( TypeInstType * typeInst ) {
     484                        if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {
     485                                // expand ttype parameter into its actual type
     486                                if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {
     487                                        delete typeInst;
     488                                        return eqvClass->type->clone();
     489                                }
     490                        }
     491                        return typeInst;
     492                }
     493        };
     494
     495        /// flattens a list of declarations, so that each tuple type has a single declaration.
     496        /// makes use of TtypeExpander to ensure ttypes are flat as well.
     497        void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {
     498                dst.clear();
     499                for ( DeclarationWithType * dcl : src ) {
     500                        PassVisitor<TtypeExpander_old> expander( env );
     501                        dcl->acceptMutator( expander );
     502                        std::list< Type * > types;
     503                        flatten( dcl->get_type(), back_inserter( types ) );
     504                        for ( Type * t : types ) {
     505                                // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.
     506                                // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.
     507                                t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);
     508
     509                                dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );
     510                        }
     511                        delete dcl;
     512                }
     513        }
     514
     515        void Unify_old::postvisit(FunctionType *functionType) {
     516                FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
     517                if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
     518                        // flatten the parameter lists for both functions so that tuple structure
     519                        // doesn't affect unification. Must be a clone so that the types don't change.
     520                        std::unique_ptr<FunctionType> flatFunc( functionType->clone() );
     521                        std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );
     522                        flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );
     523                        flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );
     524
     525                        // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
     526                        if (
     527                                        (flatFunc->parameters.size() == flatOther->parameters.size() &&
     528                                                flatFunc->returnVals.size() == flatOther->returnVals.size())
     529                                        || flatFunc->isTtype()
     530                                        || flatOther->isTtype()
     531                        ) {
     532                                if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     533                                        if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     534
     535                                                // the original types must be used in mark assertions, since pointer comparisons are used
     536                                                markAssertions( haveAssertions, needAssertions, functionType );
     537                                                markAssertions( haveAssertions, needAssertions, otherFunction );
     538
     539                                                result = true;
     540                                        } // if
     541                                } // if
     542                        } // if
     543                } // if
     544        }
     545
     546        template< typename RefType >
     547        void Unify_old::handleRefType( RefType *inst, Type *other ) {
     548                // check that other type is compatible and named the same
     549                RefType *otherStruct = dynamic_cast< RefType* >( other );
     550                result = otherStruct && inst->name == otherStruct->name;
     551        }
     552
     553        template< typename RefType >
     554        void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {
     555                // Check that other type is compatible and named the same
     556                handleRefType( inst, other );
     557                if ( ! result ) return;
     558                // Check that parameters of types unify, if any
     559                std::list< Expression* > params = inst->parameters;
     560                std::list< Expression* > otherParams = ((RefType*)other)->parameters;
     561
     562                std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();
     563                for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {
     564                        TypeExpr *param = dynamic_cast< TypeExpr* >(*it);
     565                        assertf(param, "Aggregate parameters should be type expressions");
     566                        TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);
     567                        assertf(otherParam, "Aggregate parameters should be type expressions");
     568
     569                        Type* paramTy = param->get_type();
     570                        Type* otherParamTy = otherParam->get_type();
     571
     572                        bool tupleParam = Tuples::isTtype( paramTy );
     573                        bool otherTupleParam = Tuples::isTtype( otherParamTy );
     574
     575                        if ( tupleParam && otherTupleParam ) {
     576                                ++it; ++jt;  // skip ttype parameters for break
     577                        } else if ( tupleParam ) {
     578                                // bundle other parameters into tuple to match
     579                                std::list< Type * > binderTypes;
     580
     581                                do {
     582                                        binderTypes.push_back( otherParam->get_type()->clone() );
     583                                        ++jt;
     584
     585                                        if ( jt == otherParams.end() ) break;
     586
     587                                        otherParam = dynamic_cast< TypeExpr* >(*jt);
     588                                        assertf(otherParam, "Aggregate parameters should be type expressions");
     589                                } while (true);
     590
     591                                otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };
     592                                ++it;  // skip ttype parameter for break
     593                        } else if ( otherTupleParam ) {
     594                                // bundle parameters into tuple to match other
     595                                std::list< Type * > binderTypes;
     596
     597                                do {
     598                                        binderTypes.push_back( param->get_type()->clone() );
     599                                        ++it;
     600
     601                                        if ( it == params.end() ) break;
     602
     603                                        param = dynamic_cast< TypeExpr* >(*it);
     604                                        assertf(param, "Aggregate parameters should be type expressions");
     605                                } while (true);
     606
     607                                paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };
     608                                ++jt;  // skip ttype parameter for break
     609                        }
     610
     611                        if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {
     612                                result = false;
     613                                return;
     614                        }
     615
     616                        // ttype parameter should be last
     617                        if ( tupleParam || otherTupleParam ) break;
     618                }
     619                result = ( it == params.end() && jt == otherParams.end() );
     620        }
     621
     622        void Unify_old::postvisit(StructInstType *structInst) {
     623                handleGenericRefType( structInst, type2 );
     624        }
     625
     626        void Unify_old::postvisit(UnionInstType *unionInst) {
     627                handleGenericRefType( unionInst, type2 );
     628        }
     629
     630        void Unify_old::postvisit(EnumInstType *enumInst) {
     631                handleRefType( enumInst, type2 );
     632        }
     633
     634        void Unify_old::postvisit(TraitInstType *contextInst) {
     635                handleRefType( contextInst, type2 );
     636        }
     637
     638        void Unify_old::postvisit(TypeInstType *typeInst) {
     639                assert( openVars.find( typeInst->get_name() ) == openVars.end() );
     640                TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );
     641                if ( otherInst && typeInst->get_name() == otherInst->get_name() ) {
     642                        result = true;
     643///   } else {
     644///     NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() );
     645///     if ( nt ) {
     646///       TypeDecl *type = dynamic_cast< TypeDecl* >( nt );
     647///       assert( type );
     648///       if ( type->get_base() ) {
     649///         result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     650///       }
     651///     }
     652                } // if
     653        }
     654
     655        template< typename Iterator1, typename Iterator2 >
     656        bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     657                auto get_type = [](Type * t) { return t; };
     658                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
     659                        Type * t1 = *list1Begin;
     660                        Type * t2 = *list2Begin;
     661                        bool isTtype1 = Tuples::isTtype( t1 );
     662                        bool isTtype2 = Tuples::isTtype( t2 );
     663                        // xxx - assumes ttype must be last parameter
     664                        // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
     665                        if ( isTtype1 && ! isTtype2 ) {
     666                                // combine all of the things in list2, then unify
     667                                return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     668                        } else if ( isTtype2 && ! isTtype1 ) {
     669                                // combine all of the things in list1, then unify
     670                                return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     671                        } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
     672                                return false;
     673                        } // if
     674
     675                } // for
     676                if ( list1Begin != list1End ) {
     677                        // try unifying empty tuple type with ttype
     678                        Type * t1 = *list1Begin;
     679                        if ( Tuples::isTtype( t1 ) ) {
     680                                return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     681                        } else return false;
     682                } else if ( list2Begin != list2End ) {
     683                        // try unifying empty tuple type with ttype
     684                        Type * t2 = *list2Begin;
     685                        if ( Tuples::isTtype( t2 ) ) {
     686                                return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     687                        } else return false;
     688                } else {
     689                        return true;
     690                } // if
     691        }
     692
     693        void Unify_old::postvisit(TupleType *tupleType) {
     694                if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
     695                        std::unique_ptr<TupleType> flat1( tupleType->clone() );
     696                        std::unique_ptr<TupleType> flat2( otherTuple->clone() );
     697                        std::list<Type *> types1, types2;
     698
     699                        PassVisitor<TtypeExpander_old> expander( env );
     700                        flat1->acceptMutator( expander );
     701                        flat2->acceptMutator( expander );
     702
     703                        flatten( flat1.get(), back_inserter( types1 ) );
     704                        flatten( flat2.get(), back_inserter( types2 ) );
     705
     706                        result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );
     707                } // if
     708        }
     709
     710        void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
     711                result = dynamic_cast< VarArgsType* >( type2 );
     712        }
     713
     714        void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
     715                result = dynamic_cast< ZeroType* >( type2 );
     716        }
     717
     718        void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {
     719                result = dynamic_cast< OneType* >( type2 );
     720        }
     721
     722        Type * extractResultType( FunctionType * function ) {
     723                if ( function->get_returnVals().size() == 0 ) {
     724                        return new VoidType( Type::Qualifiers() );
     725                } else if ( function->get_returnVals().size() == 1 ) {
     726                        return function->get_returnVals().front()->get_type()->clone();
     727                } else {
     728                        std::list< Type * > types;
     729                        for ( DeclarationWithType * decl : function->get_returnVals() ) {
     730                                types.push_back( decl->get_type()->clone() );
     731                        } // for
     732                        return new TupleType( Type::Qualifiers(), types );
     733                }
    101734        }
    102735
Note: See TracChangeset for help on using the changeset viewer.