Changes in src/Tuples/TupleAssignment.cc [e580aa5:0bd3faf]
- File:
-
- 1 edited
-
src/Tuples/TupleAssignment.cc (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/Tuples/TupleAssignment.cc
re580aa5 r0bd3faf 46 46 47 47 namespace { 48 49 /// Checks if `expr` is of tuple type. 50 bool isTuple( const ast::Expr * expr ) { 51 if ( !expr ) return false; 52 assert( expr->result ); 53 return dynamic_cast< const ast::TupleType * >( expr->result->stripReferences() ); 54 } 55 56 /// Checks if `expr` is of tuple type or a cast to one. 57 bool refToTuple( const ast::Expr * expr ) { 58 assert( expr->result ); 59 // Check for function returning tuple of reference types. 60 if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) { 61 return refToTuple( castExpr->arg ); 62 } else { 63 return isTuple( expr ); 48 /// true if `expr` is of tuple type 49 bool isTuple( const ast::Expr * expr ) { 50 if ( ! expr ) return false; 51 assert( expr->result ); 52 return dynamic_cast< const ast::TupleType * >( expr->result->stripReferences() ); 64 53 } 65 } 66 67 /// Dispatcher for tuple (multiple and mass) assignment operations. 68 class TupleAssignSpotter final { 69 /// Actually finds tuple assignment operations, by subclass. 70 struct Matcher { 71 ResolvExpr::CandidateList lhs, rhs; 72 TupleAssignSpotter & spotter; 73 CodeLocation location; 74 ResolvExpr::Cost baseCost; 75 std::vector< ast::ptr< ast::ObjectDecl > > tmpDecls; 76 ast::TypeEnvironment env; 77 ast::OpenVarSet open; 78 ast::AssertionSet need; 79 80 void combineState( const ResolvExpr::Candidate & cand ) { 81 env.simpleCombine( cand.env ); 82 ast::mergeOpenVars( open, cand.open ); 83 need.insert( cand.need.begin(), cand.need.end() ); 54 55 /// true if `expr` is of tuple type or a reference to one 56 bool refToTuple( const ast::Expr * expr ) { 57 assert( expr->result ); 58 // check for function returning tuple of reference types 59 if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) { 60 return refToTuple( castExpr->arg ); 61 } else { 62 return isTuple( expr ); 84 63 } 85 86 Matcher( 87 TupleAssignSpotter & s, const CodeLocation & loc, 88 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 89 : lhs( l ), rhs( r ), spotter( s ), location( loc ), 90 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(), 91 env(), open(), need() { 92 for ( auto & cand : lhs ) combineState( *cand ); 93 for ( auto & cand : rhs ) combineState( *cand ); 64 } 65 66 /// Dispatcher for tuple (multiple and mass) assignment operations 67 class TupleAssignSpotter final { 68 /// Actually finds tuple assignment operations, by subclass 69 struct Matcher { 70 ResolvExpr::CandidateList lhs, rhs; 71 TupleAssignSpotter & spotter; 72 CodeLocation location; 73 ResolvExpr::Cost baseCost; 74 std::vector< ast::ptr< ast::ObjectDecl > > tmpDecls; 75 ast::TypeEnvironment env; 76 ast::OpenVarSet open; 77 ast::AssertionSet need; 78 79 void combineState( const ResolvExpr::Candidate & cand ) { 80 env.simpleCombine( cand.env ); 81 ast::mergeOpenVars( open, cand.open ); 82 need.insert( cand.need.begin(), cand.need.end() ); 83 } 84 85 Matcher( 86 TupleAssignSpotter & s, const CodeLocation & loc, 87 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 88 : lhs( l ), rhs( r ), spotter( s ), location( loc ), 89 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(), 90 env(), open(), need() { 91 for ( auto & cand : lhs ) combineState( *cand ); 92 for ( auto & cand : rhs ) combineState( *cand ); 93 } 94 virtual ~Matcher() = default; 95 96 virtual std::vector< ast::ptr< ast::Expr > > match() = 0; 97 98 /// removes environments from subexpressions within statement expressions, which could 99 /// throw off later passes like those in Box which rely on PolyMutator, and adds the 100 /// bindings to the env 101 struct EnvRemover { 102 /// environment to hoist ExprStmt environments to 103 ast::TypeEnvironment & tenv; 104 105 EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {} 106 107 const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) { 108 if ( stmt->expr->env ) { 109 tenv.add( *stmt->expr->env ); 110 ast::ExprStmt * mut = mutate( stmt ); 111 mut->expr.get_and_mutate()->env = nullptr; 112 return mut; 113 } 114 return stmt; 115 } 116 }; 117 118 ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) { 119 assert( expr->result && ! expr->result->isVoid() ); 120 121 ast::ObjectDecl * ret = new ast::ObjectDecl{ 122 location, namer.newName(), expr->result, new ast::SingleInit{ location, expr }, 123 ast::Storage::Classes{}, ast::Linkage::Cforall }; 124 125 // if expression type is a reference, just need an initializer, otherwise construct 126 if ( ! expr->result.as< ast::ReferenceType >() ) { 127 // resolve ctor/dtor for the new object 128 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 129 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.context ); 130 // remove environments from subexpressions of stmtExpr 131 ast::Pass< EnvRemover > rm{ env }; 132 ret->init = ctorInit->accept( rm ); 133 } 134 135 PRINT( std::cerr << "new object: " << ret << std::endl; ) 136 return ret; 137 } 138 139 ast::UntypedExpr * createFunc( 140 const std::string & fname, const ast::ObjectDecl * left, 141 const ast::ObjectDecl * right 142 ) { 143 assert( left ); 144 std::vector< ast::ptr< ast::Expr > > args; 145 args.emplace_back( new ast::VariableExpr{ location, left } ); 146 if ( right ) { args.emplace_back( new ast::VariableExpr{ location, right } ); } 147 148 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) { 149 args.front() = new ast::AddressExpr{ location, args.front() }; 150 if ( right ) { args.back() = new ast::AddressExpr{ location, args.back() }; } 151 return new ast::UntypedExpr{ 152 location, new ast::NameExpr{ location, "?=?" }, std::move(args) }; 153 } else { 154 return new ast::UntypedExpr{ 155 location, new ast::NameExpr{ location, fname }, std::move(args) }; 156 } 157 } 158 }; 159 160 /// Finds mass-assignment operations 161 struct MassAssignMatcher final : public Matcher { 162 MassAssignMatcher( 163 TupleAssignSpotter & s, const CodeLocation & loc, 164 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 165 : Matcher( s, loc, l, r ) {} 166 167 std::vector< ast::ptr< ast::Expr > > match() override { 168 static UniqueName lhsNamer( "__massassign_L" ); 169 static UniqueName rhsNamer( "__massassign_R" ); 170 // empty tuple case falls into this matcher 171 assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 ); 172 173 ast::ptr< ast::ObjectDecl > rtmp = 174 rhs.size() == 1 ? newObject( rhsNamer, rhs.front()->expr ) : nullptr; 175 176 std::vector< ast::ptr< ast::Expr > > out; 177 for ( ResolvExpr::CandidateRef & lhsCand : lhs ) { 178 // create a temporary object for each value in the LHS and create a call 179 // involving the RHS 180 ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr ); 181 out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) ); 182 tmpDecls.emplace_back( std::move( ltmp ) ); 183 } 184 if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) ); 185 186 return out; 187 } 188 }; 189 190 /// Finds multiple-assignment operations 191 struct MultipleAssignMatcher final : public Matcher { 192 MultipleAssignMatcher( 193 TupleAssignSpotter & s, const CodeLocation & loc, 194 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 195 : Matcher( s, loc, l, r ) {} 196 197 std::vector< ast::ptr< ast::Expr > > match() override { 198 static UniqueName lhsNamer( "__multassign_L" ); 199 static UniqueName rhsNamer( "__multassign_R" ); 200 201 if ( lhs.size() != rhs.size() ) return {}; 202 203 // produce a new temporary object for each value in the LHS and RHS and pairwise 204 // create the calls 205 std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp; 206 207 std::vector< ast::ptr< ast::Expr > > out; 208 for ( unsigned i = 0; i < lhs.size(); ++i ) { 209 ResolvExpr::CandidateRef & lhsCand = lhs[i]; 210 ResolvExpr::CandidateRef & rhsCand = rhs[i]; 211 212 // convert RHS to LHS type minus one reference -- important for case where LHS 213 // is && and RHS is lvalue 214 auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >(); 215 rhsCand->expr = new ast::CastExpr{ rhsCand->expr, lhsType->base }; 216 ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr ); 217 ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr ); 218 out.emplace_back( createFunc( spotter.fname, lobj, robj ) ); 219 ltmp.emplace_back( std::move( lobj ) ); 220 rtmp.emplace_back( std::move( robj ) ); 221 222 // resolve the cast expression so that rhsCand return type is bound by the cast 223 // type as needed, and transfer the resulting environment 224 ResolvExpr::CandidateFinder finder( spotter.crntFinder.context, env ); 225 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 226 assert( finder.candidates.size() == 1 ); 227 env = std::move( finder.candidates.front()->env ); 228 } 229 230 splice( tmpDecls, ltmp ); 231 splice( tmpDecls, rtmp ); 232 233 return out; 234 } 235 }; 236 237 ResolvExpr::CandidateFinder & crntFinder; 238 std::string fname; 239 std::unique_ptr< Matcher > matcher; 240 241 public: 242 TupleAssignSpotter( ResolvExpr::CandidateFinder & f ) 243 : crntFinder( f ), fname(), matcher() {} 244 245 // find left- and right-hand-sides for mass or multiple assignment 246 void spot( 247 const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args 248 ) { 249 if ( auto op = expr->func.as< ast::NameExpr >() ) { 250 // skip non-assignment functions 251 if ( ! CodeGen::isCtorDtorAssign( op->name ) ) return; 252 fname = op->name; 253 254 // handled by CandidateFinder if applicable (both odd cases) 255 if ( args.empty() || ( args.size() == 1 && CodeGen::isAssignment( fname ) ) ) { 256 return; 257 } 258 259 // look over all possible left-hand-side 260 for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) { 261 // skip non-tuple LHS 262 if ( ! refToTuple( lhsCand->expr ) ) continue; 263 264 // explode is aware of casts - ensure every LHS is sent into explode with a 265 // reference cast 266 if ( ! lhsCand->expr.as< ast::CastExpr >() ) { 267 lhsCand->expr = new ast::CastExpr{ 268 lhsCand->expr, new ast::ReferenceType{ lhsCand->expr->result } }; 269 } 270 271 // explode the LHS so that each field of a tuple-valued expr is assigned 272 ResolvExpr::CandidateList lhs; 273 explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true ); 274 for ( ResolvExpr::CandidateRef & cand : lhs ) { 275 // each LHS value must be a reference - some come in with a cast, if not 276 // just cast to reference here 277 if ( ! cand->expr->result.as< ast::ReferenceType >() ) { 278 cand->expr = new ast::CastExpr{ 279 cand->expr, new ast::ReferenceType{ cand->expr->result } }; 280 } 281 } 282 283 if ( args.size() == 1 ) { 284 // mass default-initialization/destruction 285 ResolvExpr::CandidateList rhs{}; 286 matcher.reset( new MassAssignMatcher{ *this, expr->location, lhs, rhs } ); 287 match(); 288 } else if ( args.size() == 2 ) { 289 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) { 290 ResolvExpr::CandidateList rhs; 291 if ( isTuple( rhsCand->expr ) ) { 292 // multiple assignment 293 explode( *rhsCand, crntFinder.context.symtab, back_inserter(rhs), true ); 294 matcher.reset( 295 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); 296 } else { 297 // mass assignment 298 rhs.emplace_back( rhsCand ); 299 matcher.reset( 300 new MassAssignMatcher{ *this, expr->location, lhs, rhs } ); 301 } 302 match(); 303 } 304 } else { 305 // expand all possible RHS possibilities 306 std::vector< ResolvExpr::CandidateList > rhsCands; 307 combos( 308 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) ); 309 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) { 310 // multiple assignment 311 ResolvExpr::CandidateList rhs; 312 explode( rhsCand, crntFinder.context.symtab, back_inserter(rhs), true ); 313 matcher.reset( 314 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); 315 match(); 316 } 317 } 318 } 319 } 94 320 } 95 virtual ~Matcher() = default; 96 97 virtual std::vector< ast::ptr< ast::Expr > > match() = 0; 98 99 /// Removes environments from subexpressions within statement expressions, which could 100 /// throw off later passes like those in Box which rely on PolyMutator, and adds the 101 /// bindings to the env. 102 struct EnvRemover { 103 /// Environment to hoist ExprStmt environments to. 104 ast::TypeEnvironment & tenv; 105 106 EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {} 107 108 const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) { 109 if ( stmt->expr->env ) { 110 tenv.add( *stmt->expr->env ); 111 ast::ExprStmt * mut = mutate( stmt ); 112 mut->expr.get_and_mutate()->env = nullptr; 113 return mut; 114 } 115 return stmt; 116 } 117 }; 118 119 ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) { 120 assert( expr->result && !expr->result->isVoid() ); 121 122 ast::ObjectDecl * ret = new ast::ObjectDecl( 123 location, namer.newName(), expr->result, new ast::SingleInit( location, expr ), 124 ast::Storage::Classes{}, ast::Linkage::Cforall ); 125 126 // If expression type is a reference, just need an initializer, otherwise construct. 127 if ( ! expr->result.as< ast::ReferenceType >() ) { 128 // Resolve ctor/dtor for the new object. 129 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 130 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.context ); 131 // Remove environments from subexpressions of stmtExpr. 132 ast::Pass< EnvRemover > rm( env ); 133 ret->init = ctorInit->accept( rm ); 134 } 135 136 PRINT( std::cerr << "new object: " << ret << std::endl; ) 137 return ret; 138 } 139 140 ast::UntypedExpr * createFunc( 141 const std::string & fname, const ast::ObjectDecl * left, 142 const ast::ObjectDecl * right 143 ) { 144 assert( left ); 145 std::vector< ast::ptr< ast::Expr > > args; 146 args.emplace_back( new ast::VariableExpr( location, left ) ); 147 if ( right ) { args.emplace_back( new ast::VariableExpr( location, right ) ); } 148 149 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) { 150 args.front() = new ast::AddressExpr( location, args.front() ); 151 if ( right ) { args.back() = new ast::AddressExpr( location, args.back() ); } 152 return new ast::UntypedExpr( 153 location, new ast::NameExpr( location, "?=?" ), std::move( args ) ); 154 } else { 155 return new ast::UntypedExpr( 156 location, new ast::NameExpr( location, fname ), std::move( args ) ); 157 } 321 322 void match() { 323 assert( matcher ); 324 325 std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match(); 326 327 if ( ! ( matcher->lhs.empty() && matcher->rhs.empty() ) ) { 328 // if both LHS and RHS are empty than this is the empty tuple case, wherein it's 329 // okay for newAssigns to be empty. Otherwise, return early so that no new 330 // candidates are generated 331 if ( newAssigns.empty() ) return; 332 } 333 334 ResolvExpr::CandidateList crnt; 335 // now resolve new assignments 336 for ( const ast::Expr * expr : newAssigns ) { 337 PRINT( 338 std::cerr << "== resolving tuple assign ==" << std::endl; 339 std::cerr << expr << std::endl; 340 ) 341 342 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env ); 343 finder.allowVoid = true; 344 345 try { 346 finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() ); 347 } catch (...) { 348 // no match is not failure, just that this tuple assignment is invalid 349 return; 350 } 351 352 ResolvExpr::CandidateList & cands = finder.candidates; 353 assert( cands.size() == 1 ); 354 assert( cands.front()->expr ); 355 crnt.emplace_back( std::move( cands.front() ) ); 356 } 357 358 // extract expressions from the assignment candidates to produce a list of assignments 359 // that together form a sigle candidate 360 std::vector< ast::ptr< ast::Expr > > solved; 361 for ( ResolvExpr::CandidateRef & cand : crnt ) { 362 solved.emplace_back( cand->expr ); 363 matcher->combineState( *cand ); 364 } 365 366 crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >( 367 new ast::TupleAssignExpr{ 368 matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) }, 369 std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ), 370 ResolvExpr::sumCost( crnt ) + matcher->baseCost ) ); 158 371 } 159 372 }; 160 161 /// Finds mass-assignment operations.162 struct MassAssignMatcher final : public Matcher {163 MassAssignMatcher(164 TupleAssignSpotter & s, const CodeLocation & loc,165 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )166 : Matcher( s, loc, l, r ) {}167 168 std::vector< ast::ptr< ast::Expr > > match() override {169 static UniqueName lhsNamer( "__massassign_L" );170 static UniqueName rhsNamer( "__massassign_R" );171 // Empty tuple case falls into this matcher.172 assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );173 174 ast::ptr< ast::ObjectDecl > rtmp =175 1 == rhs.size() ? newObject( rhsNamer, rhs.front()->expr ) : nullptr;176 177 std::vector< ast::ptr< ast::Expr > > out;178 for ( ResolvExpr::CandidateRef & lhsCand : lhs ) {179 // Create a temporary object for each value in180 // the LHS and create a call involving the RHS.181 ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr );182 out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) );183 tmpDecls.emplace_back( std::move( ltmp ) );184 }185 if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) );186 187 return out;188 }189 };190 191 /// Finds multiple-assignment operations.192 struct MultipleAssignMatcher final : public Matcher {193 MultipleAssignMatcher(194 TupleAssignSpotter & s, const CodeLocation & loc,195 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )196 : Matcher( s, loc, l, r ) {}197 198 std::vector< ast::ptr< ast::Expr > > match() override {199 static UniqueName lhsNamer( "__multassign_L" );200 static UniqueName rhsNamer( "__multassign_R" );201 202 if ( lhs.size() != rhs.size() ) return {};203 204 // Produce a new temporary object for each value in205 // the LHS and RHS and pairwise create the calls.206 std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp;207 208 std::vector< ast::ptr< ast::Expr > > out;209 for ( unsigned i = 0; i < lhs.size(); ++i ) {210 ResolvExpr::CandidateRef & lhsCand = lhs[i];211 ResolvExpr::CandidateRef & rhsCand = rhs[i];212 213 // Convert RHS to LHS type minus one reference --214 // important for case where LHS is && and RHS is lvalue.215 auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >();216 rhsCand->expr = new ast::CastExpr( rhsCand->expr, lhsType->base );217 ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr );218 ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr );219 out.emplace_back( createFunc( spotter.fname, lobj, robj ) );220 ltmp.emplace_back( std::move( lobj ) );221 rtmp.emplace_back( std::move( robj ) );222 223 // Resolve the cast expression so that rhsCand return type is bound224 // by the cast type as needed, and transfer the resulting environment.225 ResolvExpr::CandidateFinder finder( spotter.crntFinder.context, env );226 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );227 assert( 1 == finder.candidates.size() );228 env = std::move( finder.candidates.front()->env );229 }230 231 splice( tmpDecls, ltmp );232 splice( tmpDecls, rtmp );233 234 return out;235 }236 };237 238 ResolvExpr::CandidateFinder & crntFinder;239 std::string fname;240 std::unique_ptr< Matcher > matcher;241 242 public:243 TupleAssignSpotter( ResolvExpr::CandidateFinder & f )244 : crntFinder( f ), fname(), matcher() {}245 246 // Find left- and right-hand-sides for mass or multiple assignment.247 void spot(248 const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args249 ) {250 if ( auto op = expr->func.as< ast::NameExpr >() ) {251 // Skip non-assignment functions.252 if ( !CodeGen::isCtorDtorAssign( op->name ) ) return;253 fname = op->name;254 255 // Handled by CandidateFinder if applicable (both odd cases).256 if ( args.empty() || ( 1 == args.size() && CodeGen::isAssignment( fname ) ) ) {257 return;258 }259 260 // Look over all possible left-hand-side.261 for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) {262 // Skip non-tuple LHS.263 if ( !refToTuple( lhsCand->expr ) ) continue;264 265 // Explode is aware of casts - ensure every LHS266 // is sent into explode with a reference cast.267 if ( !lhsCand->expr.as< ast::CastExpr >() ) {268 lhsCand->expr = new ast::CastExpr(269 lhsCand->expr, new ast::ReferenceType( lhsCand->expr->result ) );270 }271 272 // Explode the LHS so that each field of a tuple-valued expr is assigned.273 ResolvExpr::CandidateList lhs;274 explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true );275 for ( ResolvExpr::CandidateRef & cand : lhs ) {276 // Each LHS value must be a reference - some come in277 // with a cast, if not just cast to reference here.278 if ( !cand->expr->result.as< ast::ReferenceType >() ) {279 cand->expr = new ast::CastExpr(280 cand->expr, new ast::ReferenceType( cand->expr->result ) );281 }282 }283 284 if ( 1 == args.size() ) {285 // Mass default-initialization/destruction.286 ResolvExpr::CandidateList rhs{};287 matcher.reset( new MassAssignMatcher( *this, expr->location, lhs, rhs ) );288 match();289 } else if ( 2 == args.size() ) {290 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) {291 ResolvExpr::CandidateList rhs;292 if ( isTuple( rhsCand->expr ) ) {293 // Multiple assignment:294 explode( *rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true );295 matcher.reset(296 new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) );297 } else {298 // Mass assignment:299 rhs.emplace_back( rhsCand );300 matcher.reset(301 new MassAssignMatcher( *this, expr->location, lhs, rhs ) );302 }303 match();304 }305 } else {306 // Expand all possible RHS possibilities.307 std::vector< ResolvExpr::CandidateList > rhsCands;308 combos(309 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) );310 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) {311 // Multiple assignment:312 ResolvExpr::CandidateList rhs;313 explode( rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true );314 matcher.reset(315 new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) );316 match();317 }318 }319 }320 }321 }322 323 void match() {324 assert( matcher );325 326 std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match();327 328 if ( !( matcher->lhs.empty() && matcher->rhs.empty() ) ) {329 // If both LHS and RHS are empty than this is the empty tuple330 // case, wherein it's okay for newAssigns to be empty. Otherwise,331 // return early so that no new candidates are generated.332 if ( newAssigns.empty() ) return;333 }334 335 ResolvExpr::CandidateList crnt;336 // Now resolve new assignments.337 for ( const ast::Expr * expr : newAssigns ) {338 PRINT(339 std::cerr << "== resolving tuple assign ==" << std::endl;340 std::cerr << expr << std::endl;341 )342 343 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env );344 finder.allowVoid = true;345 346 try {347 finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() );348 } catch (...) {349 // No match is not failure, just that this tuple assignment is invalid.350 return;351 }352 353 ResolvExpr::CandidateList & cands = finder.candidates;354 assert( 1 == cands.size() );355 assert( cands.front()->expr );356 crnt.emplace_back( std::move( cands.front() ) );357 }358 359 // extract expressions from the assignment candidates to produce a list of assignments360 // that together form a sigle candidate361 std::vector< ast::ptr< ast::Expr > > solved;362 for ( ResolvExpr::CandidateRef & cand : crnt ) {363 solved.emplace_back( cand->expr );364 matcher->combineState( *cand );365 }366 367 crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >(368 new ast::TupleAssignExpr(369 matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) ),370 std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ),371 ResolvExpr::sumCost( crnt ) + matcher->baseCost ) );372 }373 };374 375 373 } // anonymous namespace 376 374 … … 379 377 std::vector< ResolvExpr::CandidateFinder > & args 380 378 ) { 381 TupleAssignSpotter spotter ( finder );379 TupleAssignSpotter spotter{ finder }; 382 380 spotter.spot( assign, args ); 383 381 }
Note:
See TracChangeset
for help on using the changeset viewer.