Changeset 405dbb3
- Timestamp:
- Jun 7, 2024, 4:53:25 PM (6 months ago)
- Branches:
- master
- Children:
- 0188539c
- Parents:
- bf64de3
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Tuples/TupleAssignment.cpp
rbf64de3 r405dbb3 241 241 ResolvExpr::CandidateFinder & crntFinder; 242 242 std::string fname; 243 std::unique_ptr< Matcher > matcher;244 243 245 244 public: 246 245 TupleAssignSpotter( ResolvExpr::CandidateFinder & f ) 247 : crntFinder( f ), fname() , matcher(){}248 249 // Find left- and right-hand-sides for mass or multiple assignment.246 : crntFinder( f ), fname() {} 247 248 /// Find left- and right-hand-sides for mass or multiple assignment. 250 249 void spot( 251 250 const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args 252 ) { 253 if ( auto op = expr->func.as< ast::NameExpr >() ) { 254 // Skip non-assignment functions. 255 if ( !CodeGen::isCtorDtorAssign( op->name ) ) return; 256 fname = op->name; 257 258 // Handled by CandidateFinder if applicable (both odd cases). 259 if ( args.empty() || ( 1 == args.size() && CodeGen::isAssignment( fname ) ) ) { 260 return; 261 } 262 263 // Look over all possible left-hand-side. 264 for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) { 265 // Skip non-tuple LHS. 266 if ( !refToTuple( lhsCand->expr ) ) continue; 267 268 // Explode is aware of casts - ensure every LHS 269 // is sent into explode with a reference cast. 270 if ( !lhsCand->expr.as< ast::CastExpr >() ) { 271 lhsCand->expr = new ast::CastExpr( 272 lhsCand->expr, new ast::ReferenceType( lhsCand->expr->result ) ); 251 ); 252 /// Wrapper around matcher.match. 253 void match( Matcher & matcher ); 254 }; 255 256 void TupleAssignSpotter::spot( 257 const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args 258 ) { 259 // Skip non-"assignment" functions. 260 auto op = expr->func.as< ast::NameExpr >(); 261 if ( nullptr == op || !CodeGen::isCtorDtorAssign( op->name ) ) return; 262 263 // Handled by CandidateFinder if applicable (both odd cases). 264 if ( args.empty() || ( 1 == args.size() && CodeGen::isAssignment( op->name ) ) ) { 265 return; 266 } 267 268 fname = op->name; 269 270 // Look over all possible left-hand-side. 271 for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) { 272 // Skip non-tuple LHS. 273 if ( !refToTuple( lhsCand->expr ) ) continue; 274 275 // Explode is aware of casts - ensure every LHS 276 // is sent into explode with a reference cast. 277 if ( !lhsCand->expr.as< ast::CastExpr >() ) { 278 lhsCand->expr = new ast::CastExpr( 279 lhsCand->expr, new ast::ReferenceType( lhsCand->expr->result ) ); 280 } 281 282 // Explode the LHS so that each field of a tuple-valued expr is assigned. 283 ResolvExpr::CandidateList lhs; 284 explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true ); 285 for ( ResolvExpr::CandidateRef & cand : lhs ) { 286 // Each LHS value must be a reference - some come in 287 // with a cast, if not just cast to reference here. 288 if ( !cand->expr->result.as< ast::ReferenceType >() ) { 289 cand->expr = new ast::CastExpr( 290 cand->expr, new ast::ReferenceType( cand->expr->result ) ); 291 } 292 } 293 294 if ( 1 == args.size() ) { 295 // Mass default-initialization/destruction. 296 ResolvExpr::CandidateList rhs{}; 297 MassAssignMatcher matcher( *this, expr->location, lhs, rhs ); 298 match( matcher ); 299 } else if ( 2 == args.size() ) { 300 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) { 301 ResolvExpr::CandidateList rhs; 302 if ( isTuple( rhsCand->expr ) ) { 303 // Multiple assignment: 304 explode( *rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true ); 305 MultipleAssignMatcher matcher( *this, expr->location, lhs, rhs ); 306 match( matcher ); 307 } else { 308 // Mass assignment: 309 rhs.emplace_back( rhsCand ); 310 MassAssignMatcher matcher( *this, expr->location, lhs, rhs ); 311 match( matcher ); 273 312 } 274 275 // Explode the LHS so that each field of a tuple-valued expr is assigned. 276 ResolvExpr::CandidateList lhs; 277 explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true ); 278 for ( ResolvExpr::CandidateRef & cand : lhs ) { 279 // Each LHS value must be a reference - some come in 280 // with a cast, if not just cast to reference here. 281 if ( !cand->expr->result.as< ast::ReferenceType >() ) { 282 cand->expr = new ast::CastExpr( 283 cand->expr, new ast::ReferenceType( cand->expr->result ) ); 284 } 285 } 286 287 if ( 1 == args.size() ) { 288 // Mass default-initialization/destruction. 289 ResolvExpr::CandidateList rhs{}; 290 matcher.reset( new MassAssignMatcher( *this, expr->location, lhs, rhs ) ); 291 match(); 292 } else if ( 2 == args.size() ) { 293 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) { 294 ResolvExpr::CandidateList rhs; 295 if ( isTuple( rhsCand->expr ) ) { 296 // Multiple assignment: 297 explode( *rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true ); 298 matcher.reset( 299 new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) ); 300 } else { 301 // Mass assignment: 302 rhs.emplace_back( rhsCand ); 303 matcher.reset( 304 new MassAssignMatcher( *this, expr->location, lhs, rhs ) ); 305 } 306 match(); 307 } 308 } else { 309 // Expand all possible RHS possibilities. 310 std::vector< ResolvExpr::CandidateList > rhsCands; 311 combos( 312 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) ); 313 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) { 314 // Multiple assignment: 315 ResolvExpr::CandidateList rhs; 316 explode( rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true ); 317 matcher.reset( 318 new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) ); 319 match(); 320 } 321 } 322 } 323 } 324 } 325 326 void match() { 327 assert( matcher ); 328 329 std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match(); 330 331 if ( !( matcher->lhs.empty() && matcher->rhs.empty() ) ) { 332 // If both LHS and RHS are empty than this is the empty tuple 333 // case, wherein it's okay for newAssigns to be empty. Otherwise, 334 // return early so that no new candidates are generated. 335 if ( newAssigns.empty() ) return; 336 } 337 338 ResolvExpr::CandidateList crnt; 339 // Now resolve new assignments. 340 for ( const ast::Expr * expr : newAssigns ) { 341 PRINT( 342 std::cerr << "== resolving tuple assign ==" << std::endl; 343 std::cerr << expr << std::endl; 344 ) 345 346 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env ); 347 finder.allowVoid = true; 348 349 try { 350 finder.find( expr, ResolvExpr::ResolveMode::withAdjustment() ); 351 } catch (...) { 352 // No match is not failure, just that this tuple assignment is invalid. 353 return; 354 } 355 356 ResolvExpr::CandidateList & cands = finder.candidates; 357 assert( 1 == cands.size() ); 358 assert( cands.front()->expr ); 359 crnt.emplace_back( std::move( cands.front() ) ); 360 } 361 362 // extract expressions from the assignment candidates to produce a list of assignments 363 // that together form a sigle candidate 364 std::vector< ast::ptr< ast::Expr > > solved; 365 for ( ResolvExpr::CandidateRef & cand : crnt ) { 366 solved.emplace_back( cand->expr ); 367 matcher->combineState( *cand ); 368 } 369 370 crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >( 371 new ast::TupleAssignExpr( 372 matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) ), 373 std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ), 374 ResolvExpr::sumCost( crnt ) + matcher->baseCost ) ); 375 } 376 }; 313 } 314 } else { 315 // Expand all possible RHS possibilities. 316 std::vector< ResolvExpr::CandidateList > rhsCands; 317 combos( 318 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) ); 319 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) { 320 // Multiple assignment: 321 ResolvExpr::CandidateList rhs; 322 explode( rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true ); 323 MultipleAssignMatcher matcher( *this, expr->location, lhs, rhs ); 324 match( matcher ); 325 } 326 } 327 } 328 } 329 330 void TupleAssignSpotter::match( TupleAssignSpotter::Matcher & matcher ) { 331 std::vector< ast::ptr< ast::Expr > > newAssigns = matcher.match(); 332 333 if ( !( matcher.lhs.empty() && matcher.rhs.empty() ) ) { 334 // If both LHS and RHS are empty than this is the empty tuple 335 // case, wherein it's okay for newAssigns to be empty. Otherwise, 336 // return early so that no new candidates are generated. 337 if ( newAssigns.empty() ) return; 338 } 339 340 ResolvExpr::CandidateList crnt; 341 // Now resolve new assignments. 342 for ( const ast::Expr * expr : newAssigns ) { 343 PRINT( 344 std::cerr << "== resolving tuple assign ==" << std::endl; 345 std::cerr << expr << std::endl; 346 ) 347 348 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher.env ); 349 finder.allowVoid = true; 350 351 try { 352 finder.find( expr, ResolvExpr::ResolveMode::withAdjustment() ); 353 } catch (...) { 354 // No match is not failure, just that this tuple assignment is invalid. 355 return; 356 } 357 358 ResolvExpr::CandidateList & cands = finder.candidates; 359 assert( 1 == cands.size() ); 360 assert( cands.front()->expr ); 361 crnt.emplace_back( std::move( cands.front() ) ); 362 } 363 364 // extract expressions from the assignment candidates to produce a list of assignments 365 // that together form a sigle candidate 366 std::vector< ast::ptr< ast::Expr > > solved; 367 for ( ResolvExpr::CandidateRef & cand : crnt ) { 368 solved.emplace_back( cand->expr ); 369 matcher.combineState( *cand ); 370 } 371 372 crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >( 373 new ast::TupleAssignExpr( 374 matcher.location, std::move( solved ), std::move( matcher.tmpDecls ) ), 375 std::move( matcher.env ), std::move( matcher.open ), std::move( matcher.need ), 376 ResolvExpr::sumCost( crnt ) + matcher.baseCost ) ); 377 } 377 378 378 379 } // anonymous namespace
Note: See TracChangeset
for help on using the changeset viewer.