Changes in src/ResolvExpr/Resolver.cc [ef5b828:3c89751]
- File:
-
- 1 edited
-
src/ResolvExpr/Resolver.cc (modified) (48 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/Resolver.cc
ref5b828 r3c89751 562 562 // TODO: Replace *exception type with &exception type. 563 563 if ( throwStmt->get_expr() ) { 564 StructDecl * exception_decl = indexer.lookupMutableStruct( "__cfaabi_ehm__base_exception_t" ); 564 StructDecl * exception_decl = 565 indexer.lookupStruct( "__cfaabi_ehm__base_exception_t" ); 565 566 assert( exception_decl ); 566 567 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, exception_decl ) ); … … 971 972 /// Calls the CandidateFinder and finds the single best candidate 972 973 CandidateRef findUnfinishedKindExpression( 973 const ast::Expr * untyped, const ast::SymbolTable & symtab, const std::string & kind, 974 const ast::Expr * untyped, const ast::SymbolTable & symtab, const std::string & kind, 974 975 std::function<bool(const Candidate &)> pred = anyCandidate, ResolvMode mode = {} 975 976 ) { … … 993 994 // produce invalid error if no candidates 994 995 if ( candidates.empty() ) { 995 SemanticError( untyped, 996 toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""), 996 SemanticError( untyped, 997 toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""), 997 998 "expression: ") ); 998 999 } … … 1030 1031 if ( winners.size() != 1 ) { 1031 1032 std::ostringstream stream; 1032 stream << "Cannot choose between " << winners.size() << " alternatives for " 1033 stream << "Cannot choose between " << winners.size() << " alternatives for " 1033 1034 << kind << (kind != "" ? " " : "") << "expression\n"; 1034 1035 ast::print( stream, untyped ); … … 1053 1054 struct StripCasts_new final { 1054 1055 const ast::Expr * postmutate( const ast::CastExpr * castExpr ) { 1055 if ( 1056 castExpr->isGenerated 1057 && typesCompatible( castExpr->arg->result, castExpr->result ) 1056 if ( 1057 castExpr->isGenerated 1058 && typesCompatible( castExpr->arg->result, castExpr->result ) 1058 1059 ) { 1059 1060 // generated cast is the same type as its argument, remove it after keeping env 1060 return ast::mutate_field( 1061 return ast::mutate_field( 1061 1062 castExpr->arg.get(), &ast::Expr::env, castExpr->env ); 1062 1063 } … … 1087 1088 1088 1089 /// Establish post-resolver invariants for expressions 1089 void finishExpr( 1090 ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env, 1090 void finishExpr( 1091 ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env, 1091 1092 const ast::TypeSubstitution * oldenv = nullptr 1092 1093 ) { 1093 1094 // set up new type substitution for expression 1094 ast::ptr< ast::TypeSubstitution > newenv = 1095 ast::ptr< ast::TypeSubstitution > newenv = 1095 1096 oldenv ? oldenv : new ast::TypeSubstitution{}; 1096 1097 env.writeToSubstitution( *newenv.get_and_mutate() ); … … 1101 1102 } // anonymous namespace 1102 1103 1103 1104 1104 1105 ast::ptr< ast::Expr > resolveInVoidContext( 1105 1106 const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env 1106 1107 ) { 1107 1108 assertf( expr, "expected a non-null expression" ); 1108 1109 1109 1110 // set up and resolve expression cast to void 1110 1111 ast::CastExpr * untyped = new ast::CastExpr{ expr }; 1111 CandidateRef choice = findUnfinishedKindExpression( 1112 CandidateRef choice = findUnfinishedKindExpression( 1112 1113 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() ); 1113 1114 1114 1115 // a cast expression has either 0 or 1 interpretations (by language rules); 1115 1116 // if 0, an exception has already been thrown, and this code will not run … … 1121 1122 1122 1123 namespace { 1123 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1124 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1124 1125 /// context. 1125 ast::ptr< ast::Expr > findVoidExpression( 1126 ast::ptr< ast::Expr > findVoidExpression( 1126 1127 const ast::Expr * untyped, const ast::SymbolTable & symtab 1127 1128 ) { … … 1133 1134 } 1134 1135 1135 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the 1136 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the 1136 1137 /// lowest cost, returning the resolved version 1137 1138 ast::ptr< ast::Expr > findKindExpression( 1138 const ast::Expr * untyped, const ast::SymbolTable & symtab, 1139 std::function<bool(const Candidate &)> pred = anyCandidate, 1139 const ast::Expr * untyped, const ast::SymbolTable & symtab, 1140 std::function<bool(const Candidate &)> pred = anyCandidate, 1140 1141 const std::string & kind = "", ResolvMode mode = {} 1141 1142 ) { 1142 1143 if ( ! untyped ) return {}; 1143 CandidateRef choice = 1144 CandidateRef choice = 1144 1145 findUnfinishedKindExpression( untyped, symtab, kind, pred, mode ); 1145 1146 finishExpr( choice->expr, choice->env, untyped->env ); … … 1148 1149 1149 1150 /// Resolve `untyped` to the single expression whose candidate is the best match 1150 ast::ptr< ast::Expr > findSingleExpression( 1151 const ast::Expr * untyped, const ast::SymbolTable & symtab 1151 ast::ptr< ast::Expr > findSingleExpression( 1152 const ast::Expr * untyped, const ast::SymbolTable & symtab 1152 1153 ) { 1153 1154 return findKindExpression( untyped, symtab ); … … 1169 1170 bool hasIntegralType( const Candidate & i ) { 1170 1171 const ast::Type * type = i.expr->result; 1171 1172 1172 1173 if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) { 1173 1174 return bt->isInteger(); 1174 } else if ( 1175 dynamic_cast< const ast::EnumInstType * >( type ) 1175 } else if ( 1176 dynamic_cast< const ast::EnumInstType * >( type ) 1176 1177 || dynamic_cast< const ast::ZeroType * >( type ) 1177 1178 || dynamic_cast< const ast::OneType * >( type ) … … 1182 1183 1183 1184 /// Resolve `untyped` as an integral expression, returning the resolved version 1184 ast::ptr< ast::Expr > findIntegralExpression( 1185 const ast::Expr * untyped, const ast::SymbolTable & symtab 1185 ast::ptr< ast::Expr > findIntegralExpression( 1186 const ast::Expr * untyped, const ast::SymbolTable & symtab 1186 1187 ) { 1187 1188 return findKindExpression( untyped, symtab, hasIntegralType, "condition" ); … … 1191 1192 bool isCharType( const ast::Type * t ) { 1192 1193 if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) { 1193 return bt->kind == ast::BasicType::Char 1194 || bt->kind == ast::BasicType::SignedChar 1194 return bt->kind == ast::BasicType::Char 1195 || bt->kind == ast::BasicType::SignedChar 1195 1196 || bt->kind == ast::BasicType::UnsignedChar; 1196 1197 } … … 1252 1253 } 1253 1254 1254 ast::ptr< ast::Init > resolveCtorInit( 1255 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab 1255 ast::ptr< ast::Init > resolveCtorInit( 1256 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab 1256 1257 ) { 1257 1258 assert( ctorInit ); … … 1260 1261 } 1261 1262 1262 ast::ptr< ast::Expr > resolveStmtExpr( 1263 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab 1263 ast::ptr< ast::Expr > resolveStmtExpr( 1264 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab 1264 1265 ) { 1265 1266 assert( stmtExpr ); … … 1302 1303 1303 1304 void Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) { 1304 // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()], 1305 // class-variable `initContext` is changed multiple times because the LHS is analyzed 1306 // twice. The second analysis changes `initContext` because a function type can contain 1307 // object declarations in the return and parameter types. Therefore each value of 1308 // `initContext` is retained so the type on the first analysis is preserved and used for 1305 // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()], 1306 // class-variable `initContext` is changed multiple times because the LHS is analyzed 1307 // twice. The second analysis changes `initContext` because a function type can contain 1308 // object declarations in the return and parameter types. Therefore each value of 1309 // `initContext` is retained so the type on the first analysis is preserved and used for 1309 1310 // selecting the RHS. 1310 1311 GuardValue( currentObject ); 1311 1312 currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() }; 1312 1313 if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) { 1313 // enumerator initializers should not use the enum type to initialize, since the 1314 // enumerator initializers should not use the enum type to initialize, since the 1314 1315 // enum type is still incomplete at this point. Use `int` instead. 1315 currentObject = ast::CurrentObject{ 1316 currentObject = ast::CurrentObject{ 1316 1317 objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } }; 1317 1318 } … … 1324 1325 } 1325 1326 1326 const ast::StaticAssertDecl * Resolver_new::previsit( 1327 const ast::StaticAssertDecl * assertDecl 1327 const ast::StaticAssertDecl * Resolver_new::previsit( 1328 const ast::StaticAssertDecl * assertDecl 1328 1329 ) { 1329 return ast::mutate_field( 1330 assertDecl, &ast::StaticAssertDecl::cond, 1330 return ast::mutate_field( 1331 assertDecl, &ast::StaticAssertDecl::cond, 1331 1332 findIntegralExpression( assertDecl->cond, symtab ) ); 1332 1333 } … … 1337 1338 #warning should use new equivalent to Validate::SizeType rather than sizeType here 1338 1339 ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt }; 1339 ast::mutate_field( 1340 type, &PtrType::dimension, 1340 ast::mutate_field( 1341 type, &PtrType::dimension, 1341 1342 findSingleExpression( type->dimension, sizeType, symtab ) ); 1342 1343 } … … 1355 1356 visit_children = false; 1356 1357 assertf( exprStmt->expr, "ExprStmt has null expression in resolver" ); 1357 1358 return ast::mutate_field( 1358 1359 return ast::mutate_field( 1359 1360 exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, symtab ) ); 1360 1361 } … … 1363 1364 visit_children = false; 1364 1365 1365 asmExpr = ast::mutate_field( 1366 asmExpr = ast::mutate_field( 1366 1367 asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, symtab ) ); 1367 1368 1368 1369 if ( asmExpr->inout ) { 1369 1370 asmExpr = ast::mutate_field( 1370 1371 asmExpr, &ast::AsmExpr::inout, findVoidExpression( asmExpr->inout, symtab ) ); 1371 1372 } 1372 1373 1373 1374 return asmExpr; 1374 1375 } … … 1387 1388 1388 1389 const ast::WhileStmt * Resolver_new::previsit( const ast::WhileStmt * whileStmt ) { 1389 return ast::mutate_field( 1390 return ast::mutate_field( 1390 1391 whileStmt, &ast::WhileStmt::cond, findIntegralExpression( whileStmt->cond, symtab ) ); 1391 1392 } … … 1408 1409 GuardValue( currentObject ); 1409 1410 switchStmt = ast::mutate_field( 1410 switchStmt, &ast::SwitchStmt::cond, 1411 switchStmt, &ast::SwitchStmt::cond, 1411 1412 findIntegralExpression( switchStmt->cond, symtab ) ); 1412 1413 currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result }; … … 1419 1420 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral " 1420 1421 "expression." ); 1421 1422 ast::ptr< ast::Expr > untyped = 1422 1423 ast::ptr< ast::Expr > untyped = 1423 1424 new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type }; 1424 1425 ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, symtab ); 1425 1426 // case condition cannot have a cast in C, so it must be removed here, regardless of 1426 1427 // case condition cannot have a cast in C, so it must be removed here, regardless of 1427 1428 // whether it would perform a conversion. 1428 1429 if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) { 1429 1430 swap_and_save_env( newExpr, castExpr->arg ); 1430 1431 } 1431 1432 1432 1433 caseStmt = ast::mutate_field( caseStmt, &ast::CaseStmt::cond, newExpr ); 1433 1434 } … … 1442 1443 ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} }; 1443 1444 branchStmt = ast::mutate_field( 1444 branchStmt, &ast::BranchStmt::computedTarget, 1445 branchStmt, &ast::BranchStmt::computedTarget, 1445 1446 findSingleExpression( branchStmt->computedTarget, target, symtab ) ); 1446 1447 } … … 1452 1453 if ( returnStmt->expr ) { 1453 1454 returnStmt = ast::mutate_field( 1454 returnStmt, &ast::ReturnStmt::expr, 1455 returnStmt, &ast::ReturnStmt::expr, 1455 1456 findSingleExpression( returnStmt->expr, functionReturn, symtab ) ); 1456 1457 } … … 1461 1462 visit_children = false; 1462 1463 if ( throwStmt->expr ) { 1463 const ast::StructDecl * exceptionDecl = 1464 const ast::StructDecl * exceptionDecl = 1464 1465 symtab.lookupStruct( "__cfaabi_ehm__base_exception_t" ); 1465 1466 assert( exceptionDecl ); 1466 ast::ptr< ast::Type > exceptType = 1467 ast::ptr< ast::Type > exceptType = 1467 1468 new ast::PointerType{ new ast::StructInstType{ exceptionDecl } }; 1468 1469 throwStmt = ast::mutate_field( 1469 throwStmt, &ast::ThrowStmt::expr, 1470 throwStmt, &ast::ThrowStmt::expr, 1470 1471 findSingleExpression( throwStmt->expr, exceptType, symtab ) ); 1471 1472 } … … 1476 1477 if ( catchStmt->cond ) { 1477 1478 ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool }; 1478 catchStmt = ast::mutate_field( 1479 catchStmt, &ast::CatchStmt::cond, 1479 catchStmt = ast::mutate_field( 1480 catchStmt, &ast::CatchStmt::cond, 1480 1481 findSingleExpression( catchStmt->cond, boolType, symtab ) ); 1481 1482 } … … 1505 1506 1506 1507 if ( clause.target.args.empty() ) { 1507 SemanticError( stmt->location, 1508 SemanticError( stmt->location, 1508 1509 "Waitfor clause must have at least one mutex parameter"); 1509 1510 } 1510 1511 1511 1512 // Find all alternatives for all arguments in canonical form 1512 std::vector< CandidateFinder > argFinders = 1513 std::vector< CandidateFinder > argFinders = 1513 1514 funcFinder.findSubExprs( clause.target.args ); 1514 1515 1515 1516 // List all combinations of arguments 1516 1517 std::vector< CandidateList > possibilities; … … 1518 1519 1519 1520 // For every possible function: 1520 // * try matching the arguments to the parameters, not the other way around because 1521 // * try matching the arguments to the parameters, not the other way around because 1521 1522 // more arguments than parameters 1522 1523 CandidateList funcCandidates; … … 1525 1526 for ( CandidateRef & func : funcFinder.candidates ) { 1526 1527 try { 1527 auto pointerType = dynamic_cast< const ast::PointerType * >( 1528 auto pointerType = dynamic_cast< const ast::PointerType * >( 1528 1529 func->expr->result->stripReferences() ); 1529 1530 if ( ! pointerType ) { 1530 SemanticError( stmt->location, func->expr->result.get(), 1531 SemanticError( stmt->location, func->expr->result.get(), 1531 1532 "candidate not viable: not a pointer type\n" ); 1532 1533 } … … 1534 1535 auto funcType = pointerType->base.as< ast::FunctionType >(); 1535 1536 if ( ! funcType ) { 1536 SemanticError( stmt->location, func->expr->result.get(), 1537 SemanticError( stmt->location, func->expr->result.get(), 1537 1538 "candidate not viable: not a function type\n" ); 1538 1539 } … … 1543 1544 1544 1545 if( ! nextMutex( param, paramEnd ) ) { 1545 SemanticError( stmt->location, funcType, 1546 SemanticError( stmt->location, funcType, 1546 1547 "candidate function not viable: no mutex parameters\n"); 1547 1548 } … … 1559 1560 ast::AssertionSet need, have; 1560 1561 ast::TypeEnvironment resultEnv{ func->env }; 1561 // Add all type variables as open so that those not used in the 1562 // Add all type variables as open so that those not used in the 1562 1563 // parameter list are still considered open 1563 1564 resultEnv.add( funcType->forall ); … … 1579 1580 unsigned n_mutex_param = 0; 1580 1581 1581 // For every argument of its set, check if it matches one of the 1582 // For every argument of its set, check if it matches one of the 1582 1583 // parameters. The order is important 1583 1584 for ( auto & arg : argsList ) { … … 1586 1587 // We ran out of parameters but still have arguments. 1587 1588 // This function doesn't match 1588 SemanticError( stmt->location, funcType, 1589 SemanticError( stmt->location, funcType, 1589 1590 toString("candidate function not viable: too many mutex " 1590 1591 "arguments, expected ", n_mutex_param, "\n" ) ); … … 1593 1594 ++n_mutex_param; 1594 1595 1595 // Check if the argument matches the parameter type in the current 1596 // Check if the argument matches the parameter type in the current 1596 1597 // scope 1597 1598 ast::ptr< ast::Type > paramType = (*param)->get_type(); 1598 if ( 1599 ! unify( 1600 arg->expr->result, paramType, resultEnv, need, have, open, 1601 symtab ) 1599 if ( 1600 ! unify( 1601 arg->expr->result, paramType, resultEnv, need, have, open, 1602 symtab ) 1602 1603 ) { 1603 1604 // Type doesn't match … … 1626 1627 } while ( nextMutex( param, paramEnd ) ); 1627 1628 1628 // We ran out of arguments but still have parameters left; this 1629 // We ran out of arguments but still have parameters left; this 1629 1630 // function doesn't match 1630 SemanticError( stmt->location, funcType, 1631 SemanticError( stmt->location, funcType, 1631 1632 toString( "candidate function not viable: too few mutex " 1632 1633 "arguments, expected ", n_mutex_param, "\n" ) ); … … 1656 1657 // Make sure correct number of arguments 1657 1658 if( funcCandidates.empty() ) { 1658 SemanticErrorException top( stmt->location, 1659 SemanticErrorException top( stmt->location, 1659 1660 "No alternatives for function in call to waitfor" ); 1660 1661 top.append( errors ); … … 1663 1664 1664 1665 if( argsCandidates.empty() ) { 1665 SemanticErrorException top( stmt->location, 1666 "No alternatives for arguments in call to waitfor" ); 1666 SemanticErrorException top( stmt->location, 1667 "No alternatives for arguments in call to waitfor" ); 1667 1668 top.append( errors ); 1668 1669 throw top; … … 1670 1671 1671 1672 if( funcCandidates.size() > 1 ) { 1672 SemanticErrorException top( stmt->location, 1673 SemanticErrorException top( stmt->location, 1673 1674 "Ambiguous function in call to waitfor" ); 1674 1675 top.append( errors ); … … 1685 1686 // build new clause 1686 1687 ast::WaitForStmt::Clause clause2; 1687 1688 1688 1689 clause2.target.func = funcCandidates.front()->expr; 1689 1690 1690 1691 clause2.target.args.reserve( clause.target.args.size() ); 1691 1692 for ( auto arg : argsCandidates.front() ) { … … 1707 1708 ast::WaitForStmt::Timeout timeout2; 1708 1709 1709 ast::ptr< ast::Type > target = 1710 ast::ptr< ast::Type > target = 1710 1711 new ast::BasicType{ ast::BasicType::LongLongUnsignedInt }; 1711 1712 timeout2.time = findSingleExpression( stmt->timeout.time, target, symtab ); … … 1739 1740 const ast::SingleInit * Resolver_new::previsit( const ast::SingleInit * singleInit ) { 1740 1741 visit_children = false; 1741 // resolve initialization using the possibilities as determined by the `currentObject` 1742 // resolve initialization using the possibilities as determined by the `currentObject` 1742 1743 // cursor. 1743 ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{ 1744 ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{ 1744 1745 singleInit->location, singleInit->value, currentObject.getOptions() }; 1745 1746 ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, symtab ); … … 1750 1751 1751 1752 // discard InitExpr wrapper and retain relevant pieces. 1752 // `initExpr` may have inferred params in the case where the expression specialized a 1753 // function pointer, and newExpr may already have inferParams of its own, so a simple 1753 // `initExpr` may have inferred params in the case where the expression specialized a 1754 // function pointer, and newExpr may already have inferParams of its own, so a simple 1754 1755 // swap is not sufficient 1755 1756 ast::Expr::InferUnion inferred = initExpr->inferred; … … 1757 1758 newExpr.get_and_mutate()->inferred.splice( std::move(inferred) ); 1758 1759 1759 // get the actual object's type (may not exactly match what comes back from the resolver 1760 // get the actual object's type (may not exactly match what comes back from the resolver 1760 1761 // due to conversions) 1761 1762 const ast::Type * initContext = currentObject.getCurrentType(); … … 1769 1770 if ( auto pt = newExpr->result.as< ast::PointerType >() ) { 1770 1771 if ( isCharType( pt->base ) ) { 1771 // strip cast if we're initializing a char[] with a char* 1772 // strip cast if we're initializing a char[] with a char* 1772 1773 // e.g. char x[] = "hello" 1773 1774 if ( auto ce = newExpr.as< ast::CastExpr >() ) { … … 1792 1793 assert( listInit->designations.size() == listInit->initializers.size() ); 1793 1794 for ( unsigned i = 0; i < listInit->designations.size(); ++i ) { 1794 // iterate designations and initializers in pairs, moving the cursor to the current 1795 // iterate designations and initializers in pairs, moving the cursor to the current 1795 1796 // designated object and resolving the initializer against that object 1796 1797 listInit = ast::mutate_field_index( 1797 listInit, &ast::ListInit::designations, i, 1798 listInit, &ast::ListInit::designations, i, 1798 1799 currentObject.findNext( listInit->designations[i] ) ); 1799 1800 listInit = ast::mutate_field_index( … … 1817 1818 ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr ); 1818 1819 1819 // intrinsic single-parameter constructors and destructors do nothing. Since this was 1820 // implicitly generated, there's no way for it to have side effects, so get rid of it to 1820 // intrinsic single-parameter constructors and destructors do nothing. Since this was 1821 // implicitly generated, there's no way for it to have side effects, so get rid of it to 1821 1822 // clean up generated code 1822 1823 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
Note:
See TracChangeset
for help on using the changeset viewer.