Ignore:
Timestamp:
Jan 9, 2017, 3:37:36 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:
627f585
Parents:
6c3a988f
Message:

address exprs are now only exploded for tuple assignments

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Tuples/TupleAssignment.cc

    r6c3a988f rf831177  
    4242          private:
    4343                void match();
    44                 void handleEmptyTuple( const ResolvExpr::AltList & alts );
    4544
    4645                struct Matcher {
     
    7473        };
    7574
    76         /// true if expr is an expression of tuple type, i.e. a tuple expression, tuple variable, or MRV (multiple-return-value) function
     75        /// true if expr is an expression of tuple type
    7776        bool isTuple( Expression *expr ) {
    7877                if ( ! expr ) return false;
    7978                assert( expr->has_result() );
    80                 return dynamic_cast<TupleExpr *>(expr) || expr->get_result()->size() > 1;
     79                return dynamic_cast< TupleType * >( expr->get_result() );
    8180        }
    8281
     
    131130                                                }
    132131                                                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 );
    142132                                        }
    143133                                }
     
    152142                matcher->match( new_assigns );
    153143
    154                 if ( new_assigns.empty() ) return;
     144                if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {
     145                        // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.
     146                        // if not the empty tuple case, return early so that no new alternatives are generated.
     147                        if ( new_assigns.empty() ) return;
     148                }
    155149                ResolvExpr::AltList current;
    156150                // now resolve new assignments
     
    196190
    197191                // explode the lhs so that each field of the tuple-valued-expr is assigned.
    198                 explode( lhsAlt, spotter.currentFinder.get_indexer(), back_inserter(lhs) );
     192                explode( lhsAlt, spotter.currentFinder.get_indexer(), back_inserter(lhs), true );
    199193
    200194                // and finally, re-add the cast to each lhs expr, so that qualified tuple fields can be constructed
     
    221215        TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
    222216                // explode the rhs so that each field of the tuple-valued-expr is assigned.
    223                 explode( std::next(alts.begin(), 1), alts.end(), spotter.currentFinder.get_indexer(), back_inserter(rhs) );
     217                explode( std::next(alts.begin(), 1), alts.end(), spotter.currentFinder.get_indexer(), back_inserter(rhs), true );
    224218        }
    225219
     
    258252                static UniqueName lhsNamer( "__massassign_L" );
    259253                static UniqueName rhsNamer( "__massassign_R" );
    260                 assert( ! lhs.empty() && rhs.size() <= 1 );
     254                // empty tuple case falls into this matcher, hence the second part of the assert
     255                assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
    261256
    262257                ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
    263258                for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
     259                        // create a temporary object for each value in the lhs and create a call involving the rhs
    264260                        ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
    265261                        out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
     
    273269                static UniqueName rhsNamer( "__multassign_R" );
    274270
    275                 // xxx - need more complicated matching?
    276271                if ( lhs.size() == rhs.size() ) {
     272                        // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls
    277273                        std::list< ObjectDecl * > ltmp;
    278274                        std::list< ObjectDecl * > rtmp;
     
    288284                }
    289285        }
    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         }
    310286} // namespace Tuples
    311287
Note: See TracChangeset for help on using the changeset viewer.