Changeset c6b4432 for src/ResolvExpr/Resolver.cc
- Timestamp:
- Nov 8, 2023, 2:01:11 PM (12 months ago)
- Branches:
- master
- Children:
- 3e4bf0d, f5ec35a
- Parents:
- 790d835
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/Resolver.cc
r790d835 rc6b4432 19 19 #include <vector> // for vector 20 20 21 #include "Alternative.h" // for Alternative, AltList22 #include "AlternativeFinder.h" // for AlternativeFinder, resolveIn...23 21 #include "Candidate.hpp" 24 22 #include "CandidateFinder.hpp" … … 40 38 #include "Common/Eval.h" // for eval 41 39 #include "Common/Iterate.hpp" // for group_iterate 42 #include "Common/PassVisitor.h" // for PassVisitor43 40 #include "Common/SemanticError.h" // for SemanticError 44 41 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 45 42 #include "Common/ToString.hpp" // for toCString 43 #include "Common/UniqueName.h" // for UniqueName 46 44 #include "InitTweak/GenInit.h" 47 45 #include "InitTweak/InitTweak.h" // for isIntrinsicSingleArgCallStmt 48 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment49 #include "SymTab/Autogen.h" // for SizeType50 #include "SymTab/Indexer.h" // for Indexer51 46 #include "SymTab/Mangler.h" // for Mangler 52 #include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar...53 #include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr54 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit55 #include "SynTree/Statement.h" // for ForStmt, Statement, BranchStmt56 #include "SynTree/Type.h" // for Type, BasicType, PointerType57 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution58 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept59 47 #include "Tuples/Tuples.h" 60 48 #include "Validate/FindSpecialDecls.h" // for SizeType … … 63 51 64 52 namespace ResolvExpr { 65 struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {66 Resolver_old() {}67 Resolver_old( const SymTab::Indexer & other ) {68 indexer = other;69 }70 71 void previsit( FunctionDecl * functionDecl );72 void postvisit( FunctionDecl * functionDecl );73 void previsit( ObjectDecl * objectDecll );74 void previsit( EnumDecl * enumDecl );75 void previsit( StaticAssertDecl * assertDecl );76 77 void previsit( ArrayType * at );78 void previsit( PointerType * at );79 80 void previsit( ExprStmt * exprStmt );81 void previsit( AsmExpr * asmExpr );82 void previsit( AsmStmt * asmStmt );83 void previsit( IfStmt * ifStmt );84 void previsit( WhileDoStmt * whileDoStmt );85 void previsit( ForStmt * forStmt );86 void previsit( SwitchStmt * switchStmt );87 void previsit( CaseStmt * caseStmt );88 void previsit( BranchStmt * branchStmt );89 void previsit( ReturnStmt * returnStmt );90 void previsit( ThrowStmt * throwStmt );91 void previsit( CatchStmt * catchStmt );92 void postvisit( CatchStmt * catchStmt );93 void previsit( WaitForStmt * stmt );94 95 void previsit( SingleInit * singleInit );96 void previsit( ListInit * listInit );97 void previsit( ConstructorInit * ctorInit );98 private:99 typedef std::list< Initializer * >::iterator InitIterator;100 101 template< typename PtrType >102 void handlePtrType( PtrType * type );103 104 void fallbackInit( ConstructorInit * ctorInit );105 106 Type * functionReturn = nullptr;107 CurrentObject currentObject = nullptr;108 bool inEnumDecl = false;109 };110 111 struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {112 void previsit( FunctionDecl * );113 void previsit( WithStmt * );114 115 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );116 };117 118 void resolve( std::list< Declaration * > translationUnit ) {119 PassVisitor<Resolver_old> resolver;120 acceptAll( translationUnit, resolver );121 }122 123 void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {124 PassVisitor<Resolver_old> resolver( indexer );125 maybeAccept( decl, resolver );126 }127 128 namespace {129 struct DeleteFinder_old : public WithShortCircuiting {130 DeletedExpr * delExpr = nullptr;131 void previsit( DeletedExpr * expr ) {132 if ( delExpr ) visit_children = false;133 else delExpr = expr;134 }135 136 void previsit( Expression * ) {137 if ( delExpr ) visit_children = false;138 }139 };140 }141 142 DeletedExpr * findDeletedExpr( Expression * expr ) {143 PassVisitor<DeleteFinder_old> finder;144 expr->accept( finder );145 return finder.pass.delExpr;146 }147 148 namespace {149 struct StripCasts_old {150 Expression * postmutate( CastExpr * castExpr ) {151 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {152 // generated cast is to the same type as its argument, so it's unnecessary -- remove it153 Expression * expr = castExpr->arg;154 castExpr->arg = nullptr;155 std::swap( expr->env, castExpr->env );156 return expr;157 }158 return castExpr;159 }160 161 static void strip( Expression *& expr ) {162 PassVisitor<StripCasts_old> stripper;163 expr = expr->acceptMutator( stripper );164 }165 };166 167 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {168 expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;169 env.makeSubstitution( *expr->env );170 StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression171 }172 173 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {174 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {175 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {176 // cast is to the same type as its argument, so it's unnecessary -- remove it177 expr = castExpr->arg;178 castExpr->arg = nullptr;179 std::swap( expr->env, castExpr->env );180 delete castExpr;181 }182 }183 }184 } // namespace185 186 namespace {187 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {188 assertf( untyped, "expected a non-null expression." );189 190 // xxx - this isn't thread-safe, but should work until we parallelize the resolver191 static unsigned recursion_level = 0;192 193 ++recursion_level;194 TypeEnvironment env;195 AlternativeFinder finder( indexer, env );196 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );197 --recursion_level;198 199 #if 0200 if ( finder.get_alternatives().size() != 1 ) {201 std::cerr << "untyped expr is ";202 untyped->print( std::cerr );203 std::cerr << std::endl << "alternatives are:";204 for ( const Alternative & alt : finder.get_alternatives() ) {205 alt.print( std::cerr );206 } // for207 } // if208 #endif209 210 // produce filtered list of alternatives211 AltList candidates;212 for ( Alternative & alt : finder.get_alternatives() ) {213 if ( pred( alt ) ) {214 candidates.push_back( std::move( alt ) );215 }216 }217 218 // produce invalid error if no candidates219 if ( candidates.empty() ) {220 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );221 }222 223 // search for cheapest candidate224 AltList winners;225 bool seen_undeleted = false;226 for ( unsigned i = 0; i < candidates.size(); ++i ) {227 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );228 229 if ( c > 0 ) continue; // skip more expensive than winner230 231 if ( c < 0 ) {232 // reset on new cheapest233 seen_undeleted = ! findDeletedExpr( candidates[i].expr );234 winners.clear();235 } else /* if ( c == 0 ) */ {236 if ( findDeletedExpr( candidates[i].expr ) ) {237 // skip deleted expression if already seen one equivalent-cost not238 if ( seen_undeleted ) continue;239 } else if ( ! seen_undeleted ) {240 // replace list of equivalent-cost deleted expressions with one non-deleted241 winners.clear();242 seen_undeleted = true;243 }244 }245 246 winners.emplace_back( std::move( candidates[i] ) );247 }248 249 // promote alternative.cvtCost to .cost250 // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost251 for ( Alternative& winner : winners ) {252 winner.cost = winner.cvtCost;253 }254 255 // produce ambiguous errors, if applicable256 if ( winners.size() != 1 ) {257 std::ostringstream stream;258 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";259 untyped->print( stream );260 stream << " Alternatives are:\n";261 printAlts( winners, stream, 1 );262 SemanticError( untyped->location, stream.str() );263 }264 265 // single selected choice266 Alternative& choice = winners.front();267 268 // fail on only expression deleted269 if ( ! seen_undeleted ) {270 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );271 }272 273 // xxx - check for ambiguous expressions274 275 // output selected choice276 alt = std::move( choice );277 }278 279 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages280 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {281 if ( ! untyped ) return;282 Alternative choice;283 findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );284 finishExpr( choice.expr, choice.env, untyped->env );285 delete untyped;286 untyped = choice.expr;287 choice.expr = nullptr;288 }289 290 bool standardAlternativeFilter( const Alternative & ) {291 // currently don't need to filter, under normal circumstances.292 // in the future, this may be useful for removing deleted expressions293 return true;294 }295 } // namespace296 297 // used in resolveTypeof298 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {299 TypeEnvironment env;300 return resolveInVoidContext( expr, indexer, env );301 }302 303 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {304 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0305 // interpretations, an exception has already been thrown.306 assertf( expr, "expected a non-null expression." );307 308 CastExpr * untyped = new CastExpr( expr ); // cast to void309 untyped->location = expr->location;310 311 // set up and resolve expression cast to void312 Alternative choice;313 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );314 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );315 assert( castExpr );316 env = std::move( choice.env );317 318 // clean up resolved expression319 Expression * ret = castExpr->arg;320 castExpr->arg = nullptr;321 322 // unlink the arg so that it isn't deleted twice at the end of the program323 untyped->arg = nullptr;324 return ret;325 }326 327 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {328 resetTyVarRenaming();329 TypeEnvironment env;330 Expression * newExpr = resolveInVoidContext( untyped, indexer, env );331 finishExpr( newExpr, env, untyped->env );332 delete untyped;333 untyped = newExpr;334 }335 336 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {337 findKindExpression( untyped, indexer, "", standardAlternativeFilter );338 }339 340 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) {341 assert( untyped && type );342 // transfer location to generated cast for error purposes343 CodeLocation location = untyped->location;344 untyped = new CastExpr( untyped, type );345 untyped->location = location;346 findSingleExpression( untyped, indexer );347 removeExtraneousCast( untyped, indexer );348 }349 350 namespace {351 bool isIntegralType( const Alternative & alt ) {352 Type * type = alt.expr->result;353 if ( dynamic_cast< EnumInstType * >( type ) ) {354 return true;355 } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {356 return bt->isInteger();357 } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {358 return true;359 } else {360 return false;361 } // if362 }363 364 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {365 findKindExpression( untyped, indexer, "condition", isIntegralType );366 }367 }368 369 370 bool isStructOrUnion( const Alternative & alt ) {371 Type * t = alt.expr->result->stripReferences();372 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );373 }374 375 void resolveWithExprs( std::list< Declaration * > & translationUnit ) {376 PassVisitor<ResolveWithExprs> resolver;377 acceptAll( translationUnit, resolver );378 }379 380 void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {381 for ( Expression *& expr : withExprs ) {382 // only struct- and union-typed expressions are viable candidates383 findKindExpression( expr, indexer, "with statement", isStructOrUnion );384 385 // if with expression might be impure, create a temporary so that it is evaluated once386 if ( Tuples::maybeImpure( expr ) ) {387 static UniqueName tmpNamer( "_with_tmp_" );388 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );389 expr = new VariableExpr( tmp );390 newStmts.push_back( new DeclStmt( tmp ) );391 if ( InitTweak::isConstructable( tmp->type ) ) {392 // generate ctor/dtor and resolve them393 tmp->init = InitTweak::genCtorInit( tmp );394 tmp->accept( *visitor );395 }396 }397 }398 }399 400 void ResolveWithExprs::previsit( WithStmt * withStmt ) {401 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );402 }403 404 void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {405 {406 // resolve with-exprs with parameters in scope and add any newly generated declarations to the407 // front of the function body.408 auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } );409 indexer.addFunctionType( functionDecl->type );410 std::list< Statement * > newStmts;411 resolveWithExprs( functionDecl->withExprs, newStmts );412 if ( functionDecl->statements ) {413 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts );414 } else {415 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() );416 }417 }418 }419 420 void Resolver_old::previsit( ObjectDecl * objectDecl ) {421 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that422 // class-variable initContext is changed multiple time because the LHS is analysed twice.423 // The second analysis changes initContext because of a function type can contain object424 // declarations in the return and parameter types. So each value of initContext is425 // retained, so the type on the first analysis is preserved and used for selecting the RHS.426 GuardValue( currentObject );427 currentObject = CurrentObject( objectDecl->get_type() );428 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {429 // enumerator initializers should not use the enum type to initialize, since430 // the enum type is still incomplete at this point. Use signed int instead.431 // TODO: BasicType::SignedInt may not longer be true432 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );433 }434 }435 436 template< typename PtrType >437 void Resolver_old::handlePtrType( PtrType * type ) {438 if ( type->get_dimension() ) {439 findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );440 }441 }442 443 void Resolver_old::previsit( ArrayType * at ) {444 handlePtrType( at );445 }446 447 void Resolver_old::previsit( PointerType * pt ) {448 handlePtrType( pt );449 }450 451 void Resolver_old::previsit( FunctionDecl * functionDecl ) {452 #if 0453 std::cerr << "resolver visiting functiondecl ";454 functionDecl->print( std::cerr );455 std::cerr << std::endl;456 #endif457 GuardValue( functionReturn );458 functionReturn = ResolvExpr::extractResultType( functionDecl->type );459 }460 461 void Resolver_old::postvisit( FunctionDecl * functionDecl ) {462 // default value expressions have an environment which shouldn't be there and trips up463 // later passes.464 // xxx - it might be necessary to somehow keep the information from this environment, but I465 // can't currently see how it's useful.466 for ( Declaration * d : functionDecl->type->parameters ) {467 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {468 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) {469 delete init->value->env;470 init->value->env = nullptr;471 }472 }473 }474 }475 476 void Resolver_old::previsit( EnumDecl * ) {477 // in case we decide to allow nested enums478 GuardValue( inEnumDecl );479 inEnumDecl = true;480 }481 482 void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {483 findIntegralExpression( assertDecl->condition, indexer );484 }485 486 void Resolver_old::previsit( ExprStmt * exprStmt ) {487 visit_children = false;488 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );489 findVoidExpression( exprStmt->expr, indexer );490 }491 492 void Resolver_old::previsit( AsmExpr * asmExpr ) {493 visit_children = false;494 findVoidExpression( asmExpr->operand, indexer );495 }496 497 void Resolver_old::previsit( AsmStmt * asmStmt ) {498 visit_children = false;499 acceptAll( asmStmt->get_input(), *visitor );500 acceptAll( asmStmt->get_output(), *visitor );501 }502 503 void Resolver_old::previsit( IfStmt * ifStmt ) {504 findIntegralExpression( ifStmt->condition, indexer );505 }506 507 void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) {508 findIntegralExpression( whileDoStmt->condition, indexer );509 }510 511 void Resolver_old::previsit( ForStmt * forStmt ) {512 if ( forStmt->condition ) {513 findIntegralExpression( forStmt->condition, indexer );514 } // if515 516 if ( forStmt->increment ) {517 findVoidExpression( forStmt->increment, indexer );518 } // if519 }520 521 void Resolver_old::previsit( SwitchStmt * switchStmt ) {522 GuardValue( currentObject );523 findIntegralExpression( switchStmt->condition, indexer );524 525 currentObject = CurrentObject( switchStmt->condition->result );526 }527 528 void Resolver_old::previsit( CaseStmt * caseStmt ) {529 if ( caseStmt->condition ) {530 std::list< InitAlternative > initAlts = currentObject.getOptions();531 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );532 // must remove cast from case statement because RangeExpr cannot be cast.533 Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );534 findSingleExpression( newExpr, indexer );535 // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.536 // Ideally we would perform the conversion internally here.537 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {538 newExpr = castExpr->arg;539 castExpr->arg = nullptr;540 std::swap( newExpr->env, castExpr->env );541 delete castExpr;542 }543 caseStmt->condition = newExpr;544 }545 }546 547 void Resolver_old::previsit( BranchStmt * branchStmt ) {548 visit_children = false;549 // must resolve the argument for a computed goto550 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement551 if ( branchStmt->computedTarget ) {552 // computed goto argument is void *553 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );554 } // if555 } // if556 }557 558 void Resolver_old::previsit( ReturnStmt * returnStmt ) {559 visit_children = false;560 if ( returnStmt->expr ) {561 findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );562 } // if563 }564 565 void Resolver_old::previsit( ThrowStmt * throwStmt ) {566 visit_children = false;567 // TODO: Replace *exception type with &exception type.568 if ( throwStmt->get_expr() ) {569 const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );570 assert( exception_decl );571 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );572 findSingleExpression( throwStmt->expr, exceptType, indexer );573 }574 }575 576 void Resolver_old::previsit( CatchStmt * catchStmt ) {577 // Until we are very sure this invarent (ifs that move between passes have then)578 // holds, check it. This allows a check for when to decode the mangling.579 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {580 assert( ifStmt->then );581 }582 // Encode the catchStmt so the condition can see the declaration.583 if ( catchStmt->cond ) {584 IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );585 catchStmt->cond = nullptr;586 catchStmt->body = ifStmt;587 }588 }589 590 void Resolver_old::postvisit( CatchStmt * catchStmt ) {591 // Decode the catchStmt so everything is stored properly.592 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );593 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {594 assert( ifStmt->condition );595 assert( ifStmt->else_ );596 catchStmt->cond = ifStmt->condition;597 catchStmt->body = ifStmt->else_;598 ifStmt->condition = nullptr;599 ifStmt->else_ = nullptr;600 delete ifStmt;601 }602 }603 604 53 template< typename iterator_t > 605 54 inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) { … … 610 59 return it != end; 611 60 } 612 613 void Resolver_old::previsit( WaitForStmt * stmt ) {614 visit_children = false;615 616 // Resolve all clauses first617 for( auto& clause : stmt->clauses ) {618 619 TypeEnvironment env;620 AlternativeFinder funcFinder( indexer, env );621 622 // Find all alternatives for a function in canonical form623 funcFinder.findWithAdjustment( clause.target.function );624 625 if ( funcFinder.get_alternatives().empty() ) {626 stringstream ss;627 ss << "Use of undeclared indentifier '";628 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name;629 ss << "' in call to waitfor";630 SemanticError( stmt->location, ss.str() );631 }632 633 if(clause.target.arguments.empty()) {634 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter");635 }636 637 // Find all alternatives for all arguments in canonical form638 std::vector< AlternativeFinder > argAlternatives;639 funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );640 641 // List all combinations of arguments642 std::vector< AltList > possibilities;643 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );644 645 AltList func_candidates;646 std::vector< AltList > args_candidates;647 648 // For every possible function :649 // try matching the arguments to the parameters650 // not the other way around because we have more arguments than parameters651 SemanticErrorException errors;652 for ( Alternative & func : funcFinder.get_alternatives() ) {653 try {654 PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() );655 if( !pointer ) {656 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" );657 }658 659 FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() );660 if( !function ) {661 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" );662 }663 664 665 {666 auto param = function->parameters.begin();667 auto param_end = function->parameters.end();668 669 if( !advance_to_mutex( param, param_end ) ) {670 SemanticError(function, "candidate function not viable: no mutex parameters\n");671 }672 }673 674 Alternative newFunc( func );675 // Strip reference from function676 referenceToRvalueConversion( newFunc.expr, newFunc.cost );677 678 // For all the set of arguments we have try to match it with the parameter of the current function alternative679 for ( auto & argsList : possibilities ) {680 681 try {682 // Declare data structures need for resolution683 OpenVarSet openVars;684 AssertionSet resultNeed, resultHave;685 TypeEnvironment resultEnv( func.env );686 makeUnifiableVars( function, openVars, resultNeed );687 // add all type variables as open variables now so that those not used in the parameter688 // list are still considered open.689 resultEnv.add( function->forall );690 691 // Load type variables from arguemnts into one shared space692 simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );693 694 // Make sure we don't widen any existing bindings695 resultEnv.forbidWidening();696 697 // Find any unbound type variables698 resultEnv.extractOpenVars( openVars );699 700 auto param = function->parameters.begin();701 auto param_end = function->parameters.end();702 703 int n_mutex_param = 0;704 705 // For every arguments of its set, check if it matches one of the parameter706 // The order is important707 for( auto & arg : argsList ) {708 709 // Ignore non-mutex arguments710 if( !advance_to_mutex( param, param_end ) ) {711 // We ran out of parameters but still have arguments712 // this function doesn't match713 SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));714 }715 716 n_mutex_param++;717 718 // Check if the argument matches the parameter type in the current scope719 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {720 // Type doesn't match721 stringstream ss;722 ss << "candidate function not viable: no known convertion from '";723 (*param)->get_type()->print( ss );724 ss << "' to '";725 arg.expr->get_result()->print( ss );726 ss << "' with env '";727 resultEnv.print(ss);728 ss << "'\n";729 SemanticError( function, ss.str() );730 }731 732 param++;733 }734 735 // All arguments match !736 737 // Check if parameters are missing738 if( advance_to_mutex( param, param_end ) ) {739 do {740 n_mutex_param++;741 param++;742 } while( advance_to_mutex( param, param_end ) );743 744 // We ran out of arguments but still have parameters left745 // this function doesn't match746 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));747 }748 749 // All parameters match !750 751 // Finish the expressions to tie in the proper environments752 finishExpr( newFunc.expr, resultEnv );753 for( Alternative & alt : argsList ) {754 finishExpr( alt.expr, resultEnv );755 }756 757 // This is a match store it and save it for later758 func_candidates.push_back( newFunc );759 args_candidates.push_back( argsList );760 761 }762 catch( SemanticErrorException & e ) {763 errors.append( e );764 }765 }766 }767 catch( SemanticErrorException & e ) {768 errors.append( e );769 }770 }771 772 // Make sure we got the right number of arguments773 if( func_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor" ); top.append( errors ); throw top; }774 if( args_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; }775 if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor" ); top.append( errors ); throw top; }776 if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor" ); top.append( errors ); throw top; }777 // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.778 779 // Swap the results from the alternative with the unresolved values.780 // Alternatives will handle deletion on destruction781 std::swap( clause.target.function, func_candidates.front().expr );782 for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) {783 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr );784 }785 786 // Resolve the conditions as if it were an IfStmt787 // Resolve the statments normally788 findSingleExpression( clause.condition, this->indexer );789 clause.statement->accept( *visitor );790 }791 792 793 if( stmt->timeout.statement ) {794 // Resolve the timeout as an size_t for now795 // Resolve the conditions as if it were an IfStmt796 // Resolve the statments normally797 findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer );798 findSingleExpression( stmt->timeout.condition, this->indexer );799 stmt->timeout.statement->accept( *visitor );800 }801 802 if( stmt->orelse.statement ) {803 // Resolve the conditions as if it were an IfStmt804 // Resolve the statments normally805 findSingleExpression( stmt->orelse.condition, this->indexer );806 stmt->orelse.statement->accept( *visitor );807 }808 }809 810 bool isCharType( Type * t ) {811 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {812 return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||813 bt->get_kind() == BasicType::UnsignedChar;814 }815 return false;816 }817 818 void Resolver_old::previsit( SingleInit * singleInit ) {819 visit_children = false;820 // resolve initialization using the possibilities as determined by the currentObject cursor821 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() );822 findSingleExpression( newExpr, indexer );823 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr );824 825 // move cursor to the object that is actually initialized826 currentObject.setNext( initExpr->get_designation() );827 828 // discard InitExpr wrapper and retain relevant pieces829 newExpr = initExpr->expr;830 initExpr->expr = nullptr;831 std::swap( initExpr->env, newExpr->env );832 // InitExpr may have inferParams in the case where the expression specializes a function833 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not834 // sufficient.835 newExpr->spliceInferParams( initExpr );836 delete initExpr;837 838 // get the actual object's type (may not exactly match what comes back from the resolver839 // due to conversions)840 Type * initContext = currentObject.getCurrentType();841 842 removeExtraneousCast( newExpr, indexer );843 844 // check if actual object's type is char[]845 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {846 if ( isCharType( at->get_base() ) ) {847 // check if the resolved type is char *848 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {849 if ( isCharType( pt->get_base() ) ) {850 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {851 // strip cast if we're initializing a char[] with a char *,852 // e.g. char x[] = "hello";853 newExpr = ce->get_arg();854 ce->set_arg( nullptr );855 std::swap( ce->env, newExpr->env );856 delete ce;857 }858 }859 }860 }861 }862 863 // set initializer expr to resolved express864 singleInit->value = newExpr;865 866 // move cursor to next object in preparation for next initializer867 currentObject.increment();868 }869 870 void Resolver_old::previsit( ListInit * listInit ) {871 visit_children = false;872 // move cursor into brace-enclosed initializer-list873 currentObject.enterListInit();874 // xxx - fix this so that the list isn't copied, iterator should be used to change current875 // element876 std::list<Designation *> newDesignations;877 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {878 // iterate designations and initializers in pairs, moving the cursor to the current879 // designated object and resolving the initializer against that object.880 Designation * des = std::get<0>(p);881 Initializer * init = std::get<1>(p);882 newDesignations.push_back( currentObject.findNext( des ) );883 init->accept( *visitor );884 }885 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list886 listInit->get_designations() = newDesignations; // xxx - memory management887 currentObject.exitListInit();888 889 // xxx - this part has not be folded into CurrentObject yet890 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {891 // Type * base = tt->get_baseType()->get_base();892 // if ( base ) {893 // // know the implementation type, so try using that as the initContext894 // ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr );895 // currentObject = &tmpObj;896 // visit( listInit );897 // } else {898 // // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context899 // Parent::visit( listInit );900 // }901 // } else {902 }903 904 // ConstructorInit - fall back on C-style initializer905 void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {906 // could not find valid constructor, or found an intrinsic constructor907 // fall back on C-style initializer908 delete ctorInit->get_ctor();909 ctorInit->set_ctor( nullptr );910 delete ctorInit->get_dtor();911 ctorInit->set_dtor( nullptr );912 maybeAccept( ctorInit->get_init(), *visitor );913 }914 915 // needs to be callable from outside the resolver, so this is a standalone function916 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {917 assert( ctorInit );918 PassVisitor<Resolver_old> resolver( indexer );919 ctorInit->accept( resolver );920 }921 922 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {923 assert( stmtExpr );924 PassVisitor<Resolver_old> resolver( indexer );925 stmtExpr->accept( resolver );926 stmtExpr->computeResult();927 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead?928 }929 930 void Resolver_old::previsit( ConstructorInit * ctorInit ) {931 visit_children = false;932 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit933 maybeAccept( ctorInit->ctor, *visitor );934 maybeAccept( ctorInit->dtor, *visitor );935 936 // found a constructor - can get rid of C-style initializer937 delete ctorInit->init;938 ctorInit->init = nullptr;939 940 // intrinsic single parameter constructors and destructors do nothing. Since this was941 // implicitly generated, there's no way for it to have side effects, so get rid of it942 // to clean up generated code.943 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {944 delete ctorInit->ctor;945 ctorInit->ctor = nullptr;946 }947 948 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {949 delete ctorInit->dtor;950 ctorInit->dtor = nullptr;951 }952 953 // xxx - todo -- what about arrays?954 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {955 // // can reduce the constructor down to a SingleInit using the956 // // second argument from the ctor call, since957 // delete ctorInit->get_ctor();958 // ctorInit->set_ctor( nullptr );959 960 // Expression * arg =961 // ctorInit->set_init( new SingleInit( arg ) );962 // }963 }964 965 ///////////////////////////////////////////////////////////////////////////966 //967 // *** NEW RESOLVER ***968 //969 ///////////////////////////////////////////////////////////////////////////970 61 971 62 namespace {
Note: See TracChangeset
for help on using the changeset viewer.