Changeset 4c8621ac


Ignore:
Timestamp:
Dec 22, 2016, 4:07:58 PM (5 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, resolv-new, with_gc
Children:
1e3d5b6
Parents:
907eccb
Message:

allow construction, destruction, and assignment for empty tuples, allow matching a ttype parameter with an empty tuple, fix specialization to work with empty tuples and void functions

Location:
src
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • src/GenPoly/Specialize.cc

    r907eccb r4c8621ac  
    3232#include "Common/utility.h"
    3333#include "InitTweak/InitTweak.h"
     34#include "Tuples/Tuples.h"
    3435
    3536namespace GenPoly {
     
    211212        // [begin, end) are the formal parameters.
    212213        // args is the list of arguments currently given to the actual function, the last of which needs to be restructured.
    213         template< typename Iterator >
    214         void fixLastArg( std::list< Expression * > & args, Iterator begin, Iterator end ) {
    215                 assertf( ! args.empty(), "Somehow args to tuple function are empty" ); // xxx - it's quite possible this will trigger for the nullary case...
    216                 Expression * last = args.back();
     214        template< typename Iterator, typename OutIterator >
     215        void fixLastArg( Expression * last, Iterator begin, Iterator end, OutIterator out ) {
    217216                // safe_dynamic_cast for the assertion
    218217                safe_dynamic_cast< TupleType * >( last->get_result() ); // xxx - it's quite possible this will trigger for the unary case...
    219                 args.pop_back(); // replace last argument in the call with
    220218                unsigned idx = 0;
    221219                for ( ; begin != end; ++begin ) {
    222220                        DeclarationWithType * formal = *begin;
    223221                        Type * formalType = formal->get_type();
    224                         matchOneFormal( last, idx, formalType, back_inserter( args ) );
     222                        matchOneFormal( last, idx, formalType, out );
    225223                }
    226224                delete last;
     
    251249
    252250                FunctionType * actualType = getFunctionType( actual->get_result() );
    253                 std::list< DeclarationWithType * >::iterator begin = actualType->get_parameters().begin();
    254                 std::list< DeclarationWithType * >::iterator end = actualType->get_parameters().end();
    255 
     251                std::list< DeclarationWithType * >::iterator actualBegin = actualType->get_parameters().begin();
     252                std::list< DeclarationWithType * >::iterator actualEnd = actualType->get_parameters().end();
     253                std::list< DeclarationWithType * >::iterator formalBegin = funType->get_parameters().begin();
     254                std::list< DeclarationWithType * >::iterator formalEnd = funType->get_parameters().end();
     255
     256                Expression * last = nullptr;
    256257                for ( DeclarationWithType* param : thunkFunc->get_functionType()->get_parameters() ) {
    257258                        // walk the parameters to the actual function alongside the parameters to the thunk to find the location where the ttype parameter begins to satisfy parameters in the actual function.
    258                         assert( begin != end );
    259                         ++begin;
    260 
    261                         // std::cerr << "thunk param: " << param << std::endl;
    262                         // last param will always be a tuple type... expand it into the actual type(?)
    263259                        param->set_name( paramNamer.newName() );
     260                        assertf( formalBegin != formalEnd, "Reached end of formal parameters before finding ttype parameter" );
     261                        if ( Tuples::isTtype((*formalBegin)->get_type()) ) {
     262                                last = new VariableExpr( param );
     263                                break;
     264                        }
     265                        assertf( actualBegin != actualEnd, "reached end of actual function's arguments before finding ttype parameter" );
     266                        ++actualBegin;
     267                        ++formalBegin;
     268
    264269                        appExpr->get_args().push_back( new VariableExpr( param ) );
    265270                } // for
    266                 fixLastArg( appExpr->get_args(), --begin, end );
     271                assert( last );
     272                fixLastArg( last, actualBegin, actualEnd, back_inserter( appExpr->get_args() ) );
    267273                appExpr->set_env( maybeClone( env ) );
    268274                if ( inferParams ) {
  • src/ResolvExpr/AlternativeFinder.cc

    r907eccb r4c8621ac  
    359359                        }
    360360                        *out++ = new TupleExpr( exprs );
     361                } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
     362                        // xxx - mixing default arguments with variadic??
     363                        std::list< Expression * > exprs;
     364                        for ( ; actualIt != actualEnd; ++actualIt ) {
     365                                exprs.push_back( actualIt->expr->clone() );
     366                                cost += actualIt->cost;
     367                        }
     368                        Expression * arg = nullptr;
     369                        if ( exprs.size() == 1 && Tuples::isTtype( exprs.front()->get_result() ) ) {
     370                                // the case where a ttype value is passed directly is special, e.g. for argument forwarding purposes
     371                                // xxx - what if passing multiple arguments, last of which is ttype?
     372                                // xxx - what would happen if unify was changed so that unifying tuple types flattened both before unifying lists? then pass in TupleType(ttype) below.
     373                                arg = exprs.front();
     374                        } else {
     375                                arg = new TupleExpr( exprs );
     376                        }
     377                        assert( arg && arg->get_result() );
     378                        if ( ! unify( ttype, arg->get_result(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
     379                                return false;
     380                        }
     381                        *out++ = arg;
     382                        return true;
    361383                } else if ( actualIt != actualEnd ) {
    362                         if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
    363                                 // xxx - mixing default arguments with variadic??
    364                                 if ( ! Tuples::isTtype( actualIt->expr->get_result() ) ) {
    365                                         // xxx - what if passing multiple arguments, last of which is ttype?
    366 
    367                                         // consume all remaining arguments, variadic style
    368                                         std::list< Expression * > exprs;
    369                                         for ( ; actualIt != actualEnd; ++actualIt ) {
    370                                                 exprs.push_back( actualIt->expr->clone() );
    371                                                 cost += actualIt->cost;
    372                                         }
    373                                         TupleExpr * arg = new TupleExpr( exprs );
    374                                         assert( arg->get_result() );
    375                                         // unification run for side effects
    376                                         bool unifyResult = unify( ttype, arg->get_result(), resultEnv, resultNeed, resultHave, openVars, indexer );
    377                                         assertf( unifyResult, "Somehow unifying ttype failed..." );
    378                                         *out++ = arg;
    379                                         return true;
    380                                 }
    381                         }
    382384                        // both actualType and formalType are atomic (non-tuple) types - if they unify
    383385                        // then accept actual as an argument, otherwise return false (fail to instantiate argument)
  • src/ResolvExpr/Unify.cc

    r907eccb r4c8621ac  
    517517                        } // if
    518518                } // for
    519                 if ( list1Begin != list1End || list2Begin != list2End ) {
    520                         return false;
     519                // if ( list1Begin != list1End || list2Begin != list2End ) {
     520                //      return false;
     521                if ( list1Begin != list1End ) {
     522                        // try unifying empty tuple type with ttype
     523                        Type * t1 = (*list1Begin)->get_type();
     524                        if ( Tuples::isTtype( t1 ) ) {
     525                                Type * combinedType = combineTypes( list2Begin, list2End );
     526                                return unifyExact( t1, combinedType, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     527                        } else return false;
     528                } else if ( list2Begin != list2End ) {
     529                        // try unifying empty tuple type with ttype
     530                        Type * t2 = (*list2Begin)->get_type();
     531                        if ( Tuples::isTtype( t2 ) ) {
     532                                Type * combinedType = combineTypes( list1Begin, list1End );
     533                                return unifyExact( combinedType, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     534                        } else return false;
    521535                } else {
    522536                        return true;
  • src/Tuples/TupleAssignment.cc

    r907eccb r4c8621ac  
    4242          private:
    4343                void match();
     44                void handleEmptyTuple( const ResolvExpr::AltList & alts );
    4445
    4546                struct Matcher {
     
    130131                                                }
    131132                                                match();
     133                                        } else {
     134                                                // handle empty case specially. It is easy to cause conflicts for tuple assignment when we consider any expression with Tuple type to be a tuple.
     135                                                // Instead, only tuple expressions and expressions with at least 2 results are considered tuples for tuple assignment. This most obviously leaves out the
     136                                                // nullary and unary cases. The unary case is handled nicely by the alternative finder as is. For example, an expression of type [int] will be exploded
     137                                                // into a list of one element (combined with the RHS elements), which will easily allow for intrinsic construction. This seems like a best case scenario anyway,
     138                                                // since intrinsic construction is much simpler from a code-gen perspective than tuple construction is.
     139                                                // This leaves the empty case, which is not easily handled by existing alternative finder logic. Instead, it seems simple enough to hanlde here that if the left
     140                                                // side is an empty tuple, then the right side is allowed to be either an empty tuple or an empty list. Fortunately, these cases are identical when exploded.
     141                                                handleEmptyTuple( *ali );
    132142                                        }
    133143                                }
     
    248258                static UniqueName lhsNamer( "__massassign_L" );
    249259                static UniqueName rhsNamer( "__massassign_R" );
    250                 assert ( ! lhs.empty() && rhs.size() <= 1);
     260                assert( ! lhs.empty() && rhs.size() <= 1 );
    251261
    252262                ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
     
    278288                }
    279289        }
     290
     291        // empty case is okay when right side is also "empty" (empty explosion handles no argument case as well as empty tuple case)
     292        void TupleAssignSpotter::handleEmptyTuple( const ResolvExpr::AltList & alts ) {
     293                assert( ! alts.empty() );
     294                Expression * lhs = alts.front().expr;
     295                if ( PointerType * ptrType = dynamic_cast< PointerType * >( lhs->get_result() ) ) {
     296                        if ( TupleType * tupleType = dynamic_cast< TupleType * >( ptrType->get_base() ) ) {
     297                                if ( tupleType->size() == 0 ) {
     298                                        ResolvExpr::AltList rhs;
     299                                        explode( std::next(alts.begin(), 1), alts.end(), currentFinder.get_indexer(), back_inserter(rhs) );
     300                                        if ( rhs.empty() ) {
     301                                                // okay, no other case is allowed
     302                                                ResolvExpr::TypeEnvironment compositeEnv;
     303                                                simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
     304                                                currentFinder.get_alternatives().push_front( ResolvExpr::Alternative( new TupleAssignExpr( std::list< Expression * >(), std::list< ObjectDecl * >() ), compositeEnv, ResolvExpr::sumCost( alts ) ) );
     305                                        }
     306                                }
     307                        }
     308                }
     309        }
    280310} // namespace Tuples
    281311
  • src/Tuples/TupleExpansion.cc

    r907eccb r4c8621ac  
    225225                                decl->get_parameters().push_back( tyParam );
    226226                        }
     227                        if ( tupleType->size() == 0 ) {
     228                                // empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.
     229                                decl->get_members().push_back( new ObjectDecl( "dummy", DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
     230                        }
    227231                        typeMap[mangleName] = decl;
    228232                        addDeclaration( decl );
Note: See TracChangeset for help on using the changeset viewer.