Changeset 7f6a7c9 for src/ResolvExpr
- Timestamp:
- Sep 21, 2022, 11:02:15 AM (3 years ago)
- Branches:
- ADT, ast-experimental, master, pthread-emulation, stuck-waitfor-destruct
- Children:
- 95dab9e
- Parents:
- 428adbc (diff), 0bd46fd (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- src/ResolvExpr
- Files:
-
- 8 edited
-
AlternativeFinder.cc (modified) (15 diffs)
-
CandidateFinder.cpp (modified) (29 diffs)
-
CommonType.cc (modified) (13 diffs)
-
ConversionCost.cc (modified) (5 diffs)
-
Resolver.cc (modified) (2 diffs)
-
SatisfyAssertions.cpp (modified) (8 diffs)
-
Unify.cc (modified) (5 diffs)
-
typeops.h (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/AlternativeFinder.cc
r428adbc r7f6a7c9 299 299 SemanticError( expr->location, stream.str() ); 300 300 } 301 alternatives = move(pruned);301 alternatives = std::move(pruned); 302 302 PRINT( 303 303 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl; … … 573 573 unsigned tupleStart = 0, Cost cost = Cost::zero, unsigned nextExpl = 0, 574 574 unsigned explAlt = 0 ) 575 : parent(parent), expr(expr->clone()), cost(cost), env( move(env)), need(move(need)),576 have( move(have)), openVars(move(openVars)), nextArg(nextArg), tupleStart(tupleStart),575 : parent(parent), expr(expr->clone()), cost(cost), env(std::move(env)), need(std::move(need)), 576 have(std::move(have)), openVars(std::move(openVars)), nextArg(nextArg), tupleStart(tupleStart), 577 577 nextExpl(nextExpl), explAlt(explAlt) {} 578 578 … … 580 580 OpenVarSet&& openVars, unsigned nextArg, Cost added ) 581 581 : parent(o.parent), expr(o.expr ? o.expr->clone() : nullptr), cost(o.cost + added), 582 env( move(env)), need(move(need)), have(move(have)), openVars(move(openVars)),582 env(std::move(env)), need(std::move(need)), have(std::move(have)), openVars(std::move(openVars)), 583 583 nextArg(nextArg), tupleStart(o.tupleStart), nextExpl(0), explAlt(0) {} 584 584 … … 707 707 if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have, 708 708 newResult.openVars, indexer ) ) { 709 finalResults.push_back( move(newResult) );709 finalResults.push_back( std::move(newResult) ); 710 710 } 711 711 … … 726 726 if ( expl.exprs.empty() ) { 727 727 results.emplace_back( 728 results[i], move(env), copy(results[i].need),729 copy(results[i].have), move(openVars), nextArg + 1, expl.cost );728 results[i], std::move(env), copy(results[i].need), 729 copy(results[i].have), std::move(openVars), nextArg + 1, expl.cost ); 730 730 731 731 continue; … … 734 734 // add new result 735 735 results.emplace_back( 736 i, expl.exprs.front().get(), move(env), copy(results[i].need),737 copy(results[i].have), move(openVars), nextArg + 1,736 i, expl.exprs.front().get(), std::move(env), copy(results[i].need), 737 copy(results[i].have), std::move(openVars), nextArg + 1, 738 738 nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 739 739 } … … 747 747 // splice final results onto results 748 748 for ( std::size_t i = 0; i < finalResults.size(); ++i ) { 749 results.push_back( move(finalResults[i]) );749 results.push_back( std::move(finalResults[i]) ); 750 750 } 751 751 return ! finalResults.empty(); … … 783 783 784 784 results.emplace_back( 785 i, expr, move(env), move(need), move(have),move(openVars), nextArg,785 i, expr, std::move(env), std::move(need), std::move(have), std::move(openVars), nextArg, 786 786 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 787 787 } … … 801 801 indexer ) ) { 802 802 results.emplace_back( 803 i, new DefaultArgExpr( cnstExpr ), move(env), move(need),move(have),804 move(openVars), nextArg, nTuples );803 i, new DefaultArgExpr( cnstExpr ), std::move(env), std::move(need), std::move(have), 804 std::move(openVars), nextArg, nTuples ); 805 805 } 806 806 } … … 824 824 if ( expl.exprs.empty() ) { 825 825 results.emplace_back( 826 results[i], move(env), move(need), move(have),move(openVars),826 results[i], std::move(env), std::move(need), std::move(have), std::move(openVars), 827 827 nextArg + 1, expl.cost ); 828 828 … … 846 846 // add new result 847 847 results.emplace_back( 848 i, expr, move(env), move(need), move(have),move(openVars), nextArg + 1,848 i, expr, std::move(env), std::move(need), std::move(have), std::move(openVars), nextArg + 1, 849 849 nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 850 850 } … … 962 962 if ( expl.exprs.empty() ) { 963 963 results.emplace_back( 964 results[i], move(env), copy(results[i].need),965 copy(results[i].have), move(openVars), nextArg + 1, expl.cost );964 results[i], std::move(env), copy(results[i].need), 965 copy(results[i].have), std::move(openVars), nextArg + 1, expl.cost ); 966 966 967 967 continue; … … 970 970 // add new result 971 971 results.emplace_back( 972 i, expl.exprs.front().get(), move(env), copy(results[i].need),973 copy(results[i].have), move(openVars), nextArg + 1, 0,972 i, expl.exprs.front().get(), std::move(env), copy(results[i].need), 973 copy(results[i].have), std::move(openVars), nextArg + 1, 0, 974 974 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 975 975 } … … 1067 1067 funcE.emplace_back( actual, indexer ); 1068 1068 } 1069 argExpansions.insert( argExpansions.begin(), move(funcE) );1069 argExpansions.insert( argExpansions.begin(), std::move(funcE) ); 1070 1070 1071 1071 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); … … 1116 1116 } // for 1117 1117 1118 candidates = move(alternatives);1118 candidates = std::move(alternatives); 1119 1119 1120 1120 // use a new list so that alternatives are not examined by addAnonConversions twice. -
src/ResolvExpr/CandidateFinder.cpp
r428adbc r7f6a7c9 269 269 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 270 270 unsigned nextExpl = 0, unsigned explAlt = 0 ) 271 : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need(move( need ) ),272 have( move( have ) ), open(move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),271 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ), 272 have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 273 273 nextExpl( nextExpl ), explAlt( explAlt ) {} 274 274 … … 276 276 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 277 277 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 278 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),279 need( move( need ) ), have( move( have ) ), open(move( open ) ), nextArg( nextArg ),278 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ), 279 need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), 280 280 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 281 281 … … 301 301 // reset pack to appropriate tuple 302 302 std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() ); 303 expr = new ast::TupleExpr{ expr->location, move( exprv ) };303 expr = new ast::TupleExpr{ expr->location, std::move( exprv ) }; 304 304 tupleStart = pack->tupleStart - 1; 305 305 parent = pack->parent; … … 404 404 newResult.open, symtab ) 405 405 ) { 406 finalResults.emplace_back( move( newResult ) );406 finalResults.emplace_back( std::move( newResult ) ); 407 407 } 408 408 … … 423 423 if ( expl.exprs.empty() ) { 424 424 results.emplace_back( 425 results[i], move( env ), copy( results[i].need ),426 copy( results[i].have ), move( open ), nextArg + 1, expl.cost );425 results[i], std::move( env ), copy( results[i].need ), 426 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost ); 427 427 428 428 continue; … … 431 431 // add new result 432 432 results.emplace_back( 433 i, expl.exprs.front(), move( env ), copy( results[i].need ),434 copy( results[i].have ), move( open ), nextArg + 1, nTuples,433 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 434 copy( results[i].have ), std::move( open ), nextArg + 1, nTuples, 435 435 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 436 436 } … … 444 444 // splice final results onto results 445 445 for ( std::size_t i = 0; i < finalResults.size(); ++i ) { 446 results.emplace_back( move( finalResults[i] ) );446 results.emplace_back( std::move( finalResults[i] ) ); 447 447 } 448 448 return ! finalResults.empty(); … … 478 478 479 479 results.emplace_back( 480 i, expr, move( env ), move( need ), move( have ),move( open ), nextArg,480 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg, 481 481 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 482 482 } … … 494 494 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 495 495 results.emplace_back( 496 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),497 move( need ), move( have ),move( open ), nextArg, nTuples );496 i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ), 497 std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples ); 498 498 } 499 499 } … … 516 516 if ( expl.exprs.empty() ) { 517 517 results.emplace_back( 518 results[i], move( env ), move( need ), move( have ),move( open ),518 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ), 519 519 nextArg + 1, expl.cost ); 520 520 … … 538 538 // add new result 539 539 results.emplace_back( 540 i, expr, move( env ), move( need ), move( have ),move( open ),540 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), 541 541 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 542 542 } … … 576 576 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 577 577 } 578 return new ast::TupleExpr{ arg->location, move( components ) };578 return new ast::TupleExpr{ arg->location, std::move( components ) }; 579 579 } else { 580 580 // handle normally … … 672 672 } 673 673 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() ); 674 appExpr->args = move( vargs );674 appExpr->args = std::move( vargs ); 675 675 // build and validate new candidate 676 676 auto newCand = … … 783 783 if ( expl.exprs.empty() ) { 784 784 results.emplace_back( 785 results[i], move( env ), copy( results[i].need ),786 copy( results[i].have ), move( open ), nextArg + 1,785 results[i], std::move( env ), copy( results[i].need ), 786 copy( results[i].have ), std::move( open ), nextArg + 1, 787 787 expl.cost ); 788 788 … … 792 792 // add new result 793 793 results.emplace_back( 794 i, expl.exprs.front(), move( env ), copy( results[i].need ),795 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost,794 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 795 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost, 796 796 expl.exprs.size() == 1 ? 0 : 1, j ); 797 797 } … … 843 843 // as a member expression 844 844 addAnonConversions( newCand ); 845 candidates.emplace_back( move( newCand ) );845 candidates.emplace_back( std::move( newCand ) ); 846 846 } 847 847 } … … 864 864 } 865 865 866 void postvisit( const ast::QualifiedNameExpr * qualifiedNameExpr ) { 867 auto mangleName = Mangle::mangle(qualifiedNameExpr->var); 868 addCandidate( qualifiedNameExpr, tenv ); 869 } 870 866 871 void postvisit( const ast::UntypedExpr * untypedExpr ) { 867 872 std::vector< CandidateFinder > argCandidates = … … 897 902 } 898 903 899 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer); 900 else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {901 const ast::EnumDecl * enumDecl = enumInst->base;902 if ( const ast::Type* enumType = enumDecl->base ) {903 // instance of enum (T) is a instance of type (T)904 funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));905 } else {906 // instance of an untyped enum is techically int907 funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));908 }909 }904 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer); 905 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) { 906 // const ast::EnumDecl * enumDecl = enumInst->base; // Here 907 // if ( const ast::Type* enumType = enumDecl->base ) { 908 // // instance of enum (T) is a instance of type (T) 909 // funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type)); 910 // } else { 911 // // instance of an untyped enum is techically int 912 // funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type)); 913 // } 914 // } 910 915 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type)); 911 916 } … … 986 991 funcE.emplace_back( *func, symtab ); 987 992 } 988 argExpansions.emplace_front( move( funcE ) );993 argExpansions.emplace_front( std::move( funcE ) ); 989 994 990 995 for ( const CandidateRef & op : opFinder ) { … … 1030 1035 if ( cvtCost != Cost::infinity ) { 1031 1036 withFunc->cvtCost = cvtCost; 1032 candidates.emplace_back( move( withFunc ) );1033 } 1034 } 1035 found = move( candidates );1037 candidates.emplace_back( std::move( withFunc ) ); 1038 } 1039 } 1040 found = std::move( candidates ); 1036 1041 1037 1042 // use a new list so that candidates are not examined by addAnonConversions twice … … 1131 1136 CandidateRef newCand = std::make_shared<Candidate>( 1132 1137 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1133 copy( cand->env ), move( open ),move( need ), cand->cost,1138 copy( cand->env ), std::move( open ), std::move( need ), cand->cost, 1134 1139 cand->cost + thisCost ); 1135 1140 inferParameters( newCand, matches ); … … 1285 1290 // as a name expression 1286 1291 addAnonConversions( newCand ); 1287 candidates.emplace_back( move( newCand ) );1292 candidates.emplace_back( std::move( newCand ) ); 1288 1293 } 1289 1294 } … … 1394 1399 new ast::LogicalExpr{ 1395 1400 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1396 move( env ), move( open ),move( need ), r1->cost + r2->cost );1401 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost ); 1397 1402 } 1398 1403 } … … 1452 1457 // output candidate 1453 1458 CandidateRef newCand = std::make_shared<Candidate>( 1454 newExpr, move( env ), move( open ),move( need ), cost );1459 newExpr, std::move( env ), std::move( open ), std::move( need ), cost ); 1455 1460 inferParameters( newCand, candidates ); 1456 1461 } … … 1519 1524 // add candidate 1520 1525 CandidateRef newCand = std::make_shared<Candidate>( 1521 newExpr, move( env ), move( open ),move( need ),1526 newExpr, std::move( env ), std::move( open ), std::move( need ), 1522 1527 r1->cost + r2->cost ); 1523 1528 inferParameters( newCand, candidates ); … … 1548 1553 1549 1554 addCandidate( 1550 new ast::TupleExpr{ tupleExpr->location, move( exprs ) },1551 move( env ), move( open ),move( need ), sumCost( subs ) );1555 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) }, 1556 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) ); 1552 1557 } 1553 1558 } … … 1635 1640 initExpr->location, restructureCast( cand->expr, toType ), 1636 1641 initAlt.designation }, 1637 move(env), move( open ),move( need ), cand->cost, thisCost );1642 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost ); 1638 1643 inferParameters( newCand, matches ); 1639 1644 } … … 1768 1773 cand->env.applyFree( newResult ); 1769 1774 cand->expr = ast::mutate_field( 1770 cand->expr.get(), &ast::Expr::result, move( newResult ) );1775 cand->expr.get(), &ast::Expr::result, std::move( newResult ) ); 1771 1776 1772 1777 out.emplace_back( cand ); … … 1854 1859 1855 1860 auto oldsize = candidates.size(); 1856 candidates = move( pruned );1861 candidates = std::move( pruned ); 1857 1862 1858 1863 PRINT( -
src/ResolvExpr/CommonType.cc
r428adbc r7f6a7c9 28 28 #include "Unify.h" // for unifyExact, WidenMode 29 29 #include "typeops.h" // for isFtype 30 #include "Tuples/Tuples.h" 30 31 31 32 // #define DEBUG … … 675 676 ast::TypeEnvironment & tenv; 676 677 const ast::OpenVarSet & open; 678 ast::AssertionSet & need; 679 ast::AssertionSet & have; 677 680 public: 678 681 static size_t traceId; … … 681 684 CommonType_new( 682 685 const ast::Type * t2, WidenMode w, const ast::SymbolTable & st, 683 ast::TypeEnvironment & env, const ast::OpenVarSet & o ) 684 : type2( t2 ), widen( w ), symtab( st ), tenv( env ), open( o ), result() {} 686 ast::TypeEnvironment & env, const ast::OpenVarSet & o, 687 ast::AssertionSet & need, ast::AssertionSet & have ) 688 : type2( t2 ), widen( w ), symtab( st ), tenv( env ), open( o ), need (need), have (have) ,result() {} 685 689 686 690 void previsit( const ast::Node * ) { visit_children = false; } … … 753 757 bool tryResolveWithTypedEnum( const ast::Type * type1 ) { 754 758 if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) { 755 ast::AssertionSet have, need; // unused756 759 ast::OpenVarSet newOpen{ open }; 757 760 if (enumInst->base->base … … 792 795 reset_qualifiers( t2 ); 793 796 794 ast::AssertionSet have, need;795 797 ast::OpenVarSet newOpen{ open }; 796 798 if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) { … … 803 805 } 804 806 } 807 else if ( isFtype (t1) && isFtype (t2) ) { 808 auto f1 = t1.as<ast::FunctionType>(); 809 if (!f1) return; 810 auto f2 = t2.strict_as<ast::FunctionType>(); 811 812 assertf(f1->returns.size() <= 1, "Function return should not be a list"); 813 assertf(f2->returns.size() <= 1, "Function return should not be a list"); 814 815 if ( 816 ( f1->params.size() != f2->params.size() || f1->returns.size() != f2->returns.size() ) 817 && ! f1->isTtype() 818 && ! f2->isTtype() 819 ) return; 820 821 auto params1 = flattenList( f1->params, tenv ); 822 auto params2 = flattenList( f2->params, tenv ); 823 824 auto crnt1 = params1.begin(); 825 auto crnt2 = params2.begin(); 826 auto end1 = params1.end(); 827 auto end2 = params2.end(); 828 829 while (crnt1 != end1 && crnt2 != end2 ) { 830 const ast::Type * arg1 = *crnt1; 831 const ast::Type * arg2 = *crnt2; 832 833 bool isTuple1 = Tuples::isTtype( t1 ); 834 bool isTuple2 = Tuples::isTtype( t2 ); 835 836 // assumes here that ttype *must* be last parameter 837 if ( isTuple1 && ! isTuple2 ) { 838 // combine remainder of list2, then unify 839 if (unifyExact( 840 arg1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open, 841 noWiden(), symtab )) { 842 break; 843 844 } 845 else return; 846 } else if ( ! isTuple1 && isTuple2 ) { 847 // combine remainder of list1, then unify 848 if (unifyExact( 849 tupleFromTypes( crnt1, end1 ), arg2, tenv, need, have, open, 850 noWiden(), symtab )) { 851 break; 852 853 } 854 else return; 855 } 856 857 // allow qualifiers of pointer and reference base to become more specific 858 if (auto ref1 = dynamic_cast<const ast::ReferenceType *> (arg1)) { 859 if (auto ref2 = dynamic_cast<const ast::ReferenceType *> (arg2)) { 860 ast::ptr<ast::Type> base1 = ref1->base; 861 ast::ptr<ast::Type> base2 = ref2->base; 862 863 // xxx - assume LHS is always the target type 864 865 if ( ! ((widen.second && ref2->qualifiers.is_mutex) 866 || (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return; 867 868 if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) { 869 870 reset_qualifiers(base1); 871 reset_qualifiers(base2); 872 873 if ( ! unifyExact( 874 base1, base2, tenv, need, have, open, noWiden(), symtab ) 875 ) return; 876 } 877 } 878 else return; 879 } 880 else if (auto ptr1 = dynamic_cast<const ast::PointerType *> (arg1)) { 881 if (auto ptr2 = dynamic_cast<const ast::PointerType *> (arg2)) { 882 ast::ptr<ast::Type> base1 = ptr1->base; 883 ast::ptr<ast::Type> base2 = ptr2->base; 884 885 // xxx - assume LHS is always the target type 886 // a function accepting const can always be called by non-const arg 887 888 if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) { 889 890 reset_qualifiers(base1); 891 reset_qualifiers(base2); 892 893 if ( ! unifyExact( 894 base1, base2, tenv, need, have, open, noWiden(), symtab ) 895 ) return; 896 } 897 } 898 else return; 899 900 } 901 else if (! unifyExact( 902 arg1, arg2, tenv, need, have, open, noWiden(), symtab )) return; 903 904 ++crnt1; ++crnt2; 905 } 906 if ( crnt1 != end1 ) { 907 // try unifying empty tuple with ttype 908 const ast::Type * t1 = *crnt1; 909 if (! Tuples::isTtype( t1 ) ) return; 910 if (! unifyExact( 911 t1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open, 912 noWiden(), symtab )) return; 913 } else if ( crnt2 != end2 ) { 914 // try unifying empty tuple with ttype 915 const ast::Type * t2 = *crnt2; 916 if (! Tuples::isTtype( t2 ) ) return; 917 if (! unifyExact( 918 tupleFromTypes( crnt1, end1 ), t2, tenv, need, have, open, 919 noWiden(), symtab )) return; 920 } 921 if ((f1->returns.size() == 0 && f2->returns.size() == 0) 922 || (f1->returns.size() == 1 && f2->returns.size() == 1 && unifyExact(f1->returns[0], f2->returns[0], tenv, need, have, open, noWiden(), symtab))) { 923 result = pointer; 924 925 for (auto & assn : f1->assertions) { 926 auto i = need.find(assn); 927 if (i != need.end()) i->second.isUsed = true; 928 auto j = have.find(assn); 929 if (j != have.end()) j->second.isUsed = true; 930 } 931 932 for (auto & assn : f2->assertions) { 933 auto i = need.find(assn); 934 if (i != need.end()) i->second.isUsed = true; 935 auto j = have.find(assn); 936 if (j != have.end()) j->second.isUsed = true; 937 } 938 939 } 940 } // if ftype 941 805 942 } 806 943 } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) { … … 839 976 reset_qualifiers( t2 ); 840 977 841 ast::AssertionSet have, need;842 978 ast::OpenVarSet newOpen{ open }; 843 979 if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) { … … 857 993 // xxx - does unifying a ref with typed enumInst makes sense? 858 994 if (!dynamic_cast<const ast::EnumInstType *>(type2)) 859 result = commonType( type2, ref, widen, symtab, tenv, open);995 result = commonType( type2, ref, tenv, need, have, open, widen, symtab ); 860 996 } 861 997 } … … 877 1013 // xxx - is this already handled by unify? 878 1014 if (!dynamic_cast<const ast::EnumInstType *>(type2)) 879 result = commonType( type2, enumInst, widen, symtab, tenv, open);1015 result = commonType( type2, enumInst, tenv, need, have, open, widen, symtab); 880 1016 } 881 1017 … … 895 1031 reset_qualifiers( t2 ); 896 1032 897 ast::AssertionSet have, need;898 1033 ast::OpenVarSet newOpen{ open }; 899 1034 if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) { … … 999 1134 ast::ptr< ast::Type > commonType( 1000 1135 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, 1001 WidenMode widen, const ast::SymbolTable & symtab, ast::TypeEnvironment & env,1002 const ast::OpenVarSet & open 1136 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 1137 const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab 1003 1138 ) { 1004 1139 unsigned depth1 = type1->referenceDepth(); … … 1036 1171 } 1037 1172 // otherwise both are reference types of the same depth and this is handled by the visitor 1038 ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open };1173 ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open, need, have }; 1039 1174 type1->accept( visitor ); 1040 1175 ast::ptr< ast::Type > result = visitor.core.result; … … 1047 1182 if ( type->base ) { 1048 1183 ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers; 1049 ast::AssertionSet have, need;1050 1184 ast::OpenVarSet newOpen{ open }; 1051 1185 -
src/ResolvExpr/ConversionCost.cc
r428adbc r7f6a7c9 22 22 #include "ResolvExpr/Cost.h" // for Cost 23 23 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment 24 #include "ResolvExpr/Unify.h" 24 25 #include "SymTab/Indexer.h" // for Indexer 25 26 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl 26 27 #include "SynTree/Type.h" // for Type, BasicType, TypeInstType 27 28 #include "typeops.h" // for typesCompatibleIgnoreQualifiers 29 28 30 29 31 namespace ResolvExpr { … … 338 340 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) { 339 341 const EnumDecl * base_enum = enumInst->baseEnum; 340 if ( const Type * base = base_enum->base ) { // if the base enum has a base (if it is typed)342 if ( const Type * base = base_enum->base ) { 341 343 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) { 342 344 conversionCostFromBasicToBasic(basicType, enumBaseAstBasic); … … 632 634 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) { 633 635 const ast::EnumDecl * enumDecl = enumInst->base.get(); 634 if ( const ast::Type * enumType = enumDecl->base.get() ) { 636 if ( enumDecl->isTyped && !enumDecl->base.get() ) { 637 cost = Cost::infinity; 638 } else if ( const ast::Type * enumType = enumDecl->base.get() ) { 635 639 if ( const ast::BasicType * enumTypeAsBasic = dynamic_cast<const ast::BasicType *>(enumType) ) { 636 640 conversionCostFromBasicToBasic( basicType, enumTypeAsBasic ); … … 655 659 cost = Cost::safe; 656 660 } 657 } else { 661 } 662 /* 663 else if ( const ast::FunctionType * dstFunc = dstAsPtr->base.as<ast::FunctionType>()) { 664 if (const ast::FunctionType * srcFunc = pointerType->base.as<ast::FunctionType>()) { 665 if (dstFunc->params.empty() && dstFunc->isVarArgs ) { 666 cost = Cost::unsafe; // assign any function to variadic fptr 667 } 668 } 669 else { 670 ast::AssertionSet need, have; // unused 671 ast::OpenVarSet open; 672 env.extractOpenVars(open); 673 ast::TypeEnvironment tenv = env; 674 if ( unify(dstAsPtr->base, pointerType->base, tenv, need, have, open, symtab) ) { 675 cost = Cost::safe; 676 } 677 } 678 // else infinity 679 } 680 */ 681 else { 658 682 int assignResult = ptrsAssignable( pointerType->base, dstAsPtr->base, env ); 659 683 if ( 0 < assignResult && tq1 <= tq2 ) { … … 694 718 const ast::EnumDecl * baseEnum = enumInstType->base; 695 719 if ( const ast::Type * baseType = baseEnum->base ) { 696 cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );720 costCalc( baseType, dst, srcIsLvalue, symtab, env ); 697 721 } else { 698 722 (void)enumInstType; -
src/ResolvExpr/Resolver.cc
r428adbc r7f6a7c9 1478 1478 // enum type is still incomplete at this point. Use `int` instead. 1479 1479 1480 if (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base) { 1480 if ( auto enumBase = dynamic_cast< const ast::EnumInstType * > 1481 ( objectDecl->get_type() )->base->base ) { 1481 1482 objectDecl = fixObjectType( objectDecl, context ); 1482 const ast::Type * enumBase = (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base.get());1483 1483 currentObject = ast::CurrentObject{ 1484 1484 objectDecl->location, … … 1493 1493 } 1494 1494 else { 1495 if ( !objectDecl->isTypeFixed) {1495 if ( !objectDecl->isTypeFixed ) { 1496 1496 auto newDecl = fixObjectType(objectDecl, context); 1497 1497 auto mutDecl = mutate(newDecl); -
src/ResolvExpr/SatisfyAssertions.cpp
r428adbc r7f6a7c9 36 36 #include "AST/SymbolTable.hpp" 37 37 #include "AST/TypeEnvironment.hpp" 38 #include "FindOpenVars.h" 38 39 #include "Common/FilterCombos.h" 39 40 #include "Common/Indenter.h" … … 161 162 162 163 /// Satisfy a single assertion 163 bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat ) {164 bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool allowConversion = false, bool skipUnbound = false) { 164 165 // skip unused assertions 165 166 if ( ! assn.second.isUsed ) return true; … … 180 181 if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer; 181 182 else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams); 183 else if (skipUnbound) return false; 182 184 183 185 candidates = sat.symtab.specialLookupId(kind, otypeKey); … … 205 207 206 208 // only keep candidates which unify 207 if ( unify( toType, adjType, newEnv, newNeed, have, newOpen, sat.symtab ) ) { 208 // set up binding slot for recursive assertions 209 ast::UniqueId crntResnSlot = 0; 210 if ( ! newNeed.empty() ) { 211 crntResnSlot = ++globalResnSlot; 212 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; } 213 } 214 215 matches.emplace_back( 216 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 217 std::move( newOpen ), crntResnSlot ); 209 210 ast::OpenVarSet closed; 211 findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed ); 212 findOpenVars( adjType, newOpen, closed, newNeed, have, FirstOpen ); 213 if ( allowConversion ) { 214 if ( auto c = commonType( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) { 215 // set up binding slot for recursive assertions 216 ast::UniqueId crntResnSlot = 0; 217 if ( ! newNeed.empty() ) { 218 crntResnSlot = ++globalResnSlot; 219 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; } 220 } 221 222 matches.emplace_back( 223 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 224 std::move( newOpen ), crntResnSlot ); 225 } 226 } 227 else { 228 if ( unifyExact( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) { 229 // set up binding slot for recursive assertions 230 ast::UniqueId crntResnSlot = 0; 231 if ( ! newNeed.empty() ) { 232 crntResnSlot = ++globalResnSlot; 233 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; } 234 } 235 236 matches.emplace_back( 237 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 238 std::move( newOpen ), crntResnSlot ); 239 } 218 240 } 219 241 } … … 413 435 // for each current mutually-compatible set of assertions 414 436 for ( SatState & sat : sats ) { 437 bool allowConversion = false; 415 438 // stop this branch if a better option is already found 416 439 auto it = thresholds.find( pruneKey( *sat.cand ) ); … … 418 441 419 442 // should a limit be imposed? worst case here is O(n^2) but very unlikely to happen. 443 420 444 for (unsigned resetCount = 0; ; ++resetCount) { 421 445 ast::AssertionList next; … … 424 448 for ( auto & assn : sat.need ) { 425 449 // fail early if any assertion is not satisfiable 426 if ( ! satisfyAssertion( assn, sat ) ) {450 if ( ! satisfyAssertion( assn, sat, allowConversion, !next.empty() ) ) { 427 451 next.emplace_back(assn); 428 452 // goto nextSat; … … 433 457 // fail if nothing resolves 434 458 else if (next.size() == sat.need.size()) { 435 Indenter tabs{ 3 }; 436 std::ostringstream ss; 437 ss << tabs << "Unsatisfiable alternative:\n"; 438 print( ss, *sat.cand, ++tabs ); 439 ss << (tabs-1) << "Could not satisfy assertion:\n"; 440 ast::print( ss, next[0].first, tabs ); 441 442 errors.emplace_back( ss.str() ); 443 goto nextSat; 444 } 459 if (allowConversion) { 460 Indenter tabs{ 3 }; 461 std::ostringstream ss; 462 ss << tabs << "Unsatisfiable alternative:\n"; 463 print( ss, *sat.cand, ++tabs ); 464 ss << (tabs-1) << "Could not satisfy assertion:\n"; 465 ast::print( ss, next[0].first, tabs ); 466 467 errors.emplace_back( ss.str() ); 468 goto nextSat; 469 } 470 471 else { 472 allowConversion = true; 473 continue; 474 } 475 } 476 allowConversion = false; 445 477 sat.need = std::move(next); 446 478 } -
src/ResolvExpr/Unify.cc
r428adbc r7f6a7c9 165 165 ast::Type * newFirst = shallowCopy( first ); 166 166 ast::Type * newSecond = shallowCopy( second ); 167 if ( auto temp = dynamic_cast<const ast::EnumInstType *>(first) ) { 168 if ( !dynamic_cast< const ast::EnumInstType * >( second ) ) { 169 const ast::EnumDecl * baseEnum = dynamic_cast<const ast::EnumDecl *>(temp->base.get()); 170 if ( auto t = baseEnum->base.get() ) { 171 newFirst = ast::shallowCopy( t ); 172 } 173 } 174 } else if ( auto temp = dynamic_cast<const ast::EnumInstType *>(second) ) { 175 const ast::EnumDecl * baseEnum = dynamic_cast<const ast::EnumDecl *>(temp->base.get()); 176 if ( auto t = baseEnum->base.get() ) { 177 newSecond = ast::shallowCopy( t ); 178 } 179 } 180 167 181 newFirst ->qualifiers = {}; 168 182 newSecond->qualifiers = {}; … … 693 707 } 694 708 709 namespace { 710 /// Replaces ttype variables with their bound types. 711 /// If this isn't done when satifying ttype assertions, then argument lists can have 712 /// different size and structure when they should be compatible. 713 struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor { 714 ast::TypeEnvironment & tenv; 715 716 TtypeExpander_new( ast::TypeEnvironment & env ) : tenv( env ) {} 717 718 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) { 719 if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) { 720 // expand ttype parameter into its actual type 721 if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) { 722 return clz->bound; 723 } 724 } 725 return typeInst; 726 } 727 }; 728 } 729 730 std::vector< ast::ptr< ast::Type > > flattenList( 731 const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env 732 ) { 733 std::vector< ast::ptr< ast::Type > > dst; 734 dst.reserve( src.size() ); 735 for ( const auto & d : src ) { 736 ast::Pass<TtypeExpander_new> expander{ env }; 737 // TtypeExpander pass is impure (may mutate nodes in place) 738 // need to make nodes shared to prevent accidental mutation 739 ast::ptr<ast::Type> dc = d->accept(expander); 740 auto types = flatten( dc ); 741 for ( ast::ptr< ast::Type > & t : types ) { 742 // outermost const, volatile, _Atomic qualifiers in parameters should not play 743 // a role in the unification of function types, since they do not determine 744 // whether a function is callable. 745 // NOTE: **must** consider at least mutex qualifier, since functions can be 746 // overloaded on outermost mutex and a mutex function has different 747 // requirements than a non-mutex function 748 remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic ); 749 dst.emplace_back( t ); 750 } 751 } 752 return dst; 753 } 754 695 755 class Unify_new final : public ast::WithShortCircuiting { 696 756 const ast::Type * type2; … … 764 824 765 825 private: 766 /// Replaces ttype variables with their bound types.767 /// If this isn't done when satifying ttype assertions, then argument lists can have768 /// different size and structure when they should be compatible.769 struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor {770 ast::TypeEnvironment & tenv;771 772 TtypeExpander_new( ast::TypeEnvironment & env ) : tenv( env ) {}773 774 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {775 if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {776 // expand ttype parameter into its actual type777 if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {778 return clz->bound;779 }780 }781 return typeInst;782 }783 };784 785 /// returns flattened version of `src`786 static std::vector< ast::ptr< ast::Type > > flattenList(787 const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env788 ) {789 std::vector< ast::ptr< ast::Type > > dst;790 dst.reserve( src.size() );791 for ( const auto & d : src ) {792 ast::Pass<TtypeExpander_new> expander{ env };793 // TtypeExpander pass is impure (may mutate nodes in place)794 // need to make nodes shared to prevent accidental mutation795 ast::ptr<ast::Type> dc = d->accept(expander);796 auto types = flatten( dc );797 for ( ast::ptr< ast::Type > & t : types ) {798 // outermost const, volatile, _Atomic qualifiers in parameters should not play799 // a role in the unification of function types, since they do not determine800 // whether a function is callable.801 // NOTE: **must** consider at least mutex qualifier, since functions can be802 // overloaded on outermost mutex and a mutex function has different803 // requirements than a non-mutex function804 remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );805 dst.emplace_back( t );806 }807 }808 return dst;809 }810 811 /// Creates a tuple type based on a list of DeclWithType812 template< typename Iter >813 static const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {814 std::vector< ast::ptr< ast::Type > > types;815 while ( crnt != end ) {816 // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure817 // that this results in a flat tuple818 flatten( *crnt, types );819 820 ++crnt;821 }822 823 return new ast::TupleType{ std::move(types) };824 }825 826 826 827 template< typename Iter > … … 1034 1035 private: 1035 1036 /// Creates a tuple type based on a list of Type 1036 static const ast::Type * tupleFromTypes( 1037 const std::vector< ast::ptr< ast::Type > > & tys 1038 ) { 1039 std::vector< ast::ptr< ast::Type > > out; 1040 for ( const ast::Type * ty : tys ) { 1041 // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure 1042 // that this results in a flat tuple 1043 flatten( ty, out ); 1044 } 1045 1046 return new ast::TupleType{ std::move(out) }; 1047 } 1037 1048 1038 1049 1039 static bool unifyList( … … 1217 1207 } 1218 1208 1219 } else if (( common = commonType( t1, t2, widen, symtab, env, open ))) {1209 } else if (( common = commonType( t1, t2, env, need, have, open, widen, symtab ))) { 1220 1210 // no exact unification, but common type 1221 1211 auto c = shallowCopy(common.get()); -
src/ResolvExpr/typeops.h
r428adbc r7f6a7c9 138 138 Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer & indexer, TypeEnvironment & env, const OpenVarSet & openVars ); 139 139 ast::ptr< ast::Type > commonType( 140 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, WidenMode widen, 141 const ast::SymbolTable & symtab, ast::TypeEnvironment & env, const ast::OpenVarSet & open ); 140 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, 141 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 142 const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab 143 ); 144 // in Unify.cc 145 std::vector< ast::ptr< ast::Type > > flattenList( 146 const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env 147 ); 142 148 143 149 // in PolyCost.cc … … 181 187 182 188 /// flatten tuple type into existing list of types 183 staticinline void flatten(189 inline void flatten( 184 190 const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out 185 191 ) { … … 194 200 195 201 /// flatten tuple type into list of types 196 staticinline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {202 inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) { 197 203 std::vector< ast::ptr< ast::Type > > out; 198 204 out.reserve( type->size() ); … … 200 206 return out; 201 207 } 208 209 template< typename Iter > 210 const ast::Type * tupleFromTypes( Iter crnt, Iter end ) { 211 std::vector< ast::ptr< ast::Type > > types; 212 while ( crnt != end ) { 213 // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure 214 // that this results in a flat tuple 215 flatten( *crnt, types ); 216 217 ++crnt; 218 } 219 220 221 return new ast::TupleType{ std::move(types) }; 222 } 223 224 inline const ast::Type * tupleFromTypes( 225 const std::vector< ast::ptr< ast::Type > > & tys 226 ) { 227 return tupleFromTypes( tys.begin(), tys.end() ); 228 } 229 230 202 231 203 232 // in TypeEnvironment.cc
Note:
See TracChangeset
for help on using the changeset viewer.