Changes in / [28f3a19:b21c77a]
- Location:
- src
- Files:
-
- 5 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Common/module.mk
r28f3a19 rb21c77a 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Peter A. Buhr13 ## Last Modified On : T ue Sep 27 11:06:38 201614 ## Update Count : 412 ## Last Modified By : Aaron B. Moss 13 ## Last Modified On : Thu Jun 14 11:15:00 2018 14 ## Update Count : 5 15 15 ############################################################################### 16 16 … … 20 20 Common/GC.cc \ 21 21 Common/Assert.cc \ 22 Common/InternedString.cc \ 22 23 Common/Heap.cc -
src/GenPoly/Box.cc
r28f3a19 rb21c77a 38 38 #include "Lvalue.h" // for generalizedLvalue 39 39 #include "Parser/LinkageSpec.h" // for C, Spec, Cforall, Intrinsic 40 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass41 40 #include "ResolvExpr/typeops.h" // for typesCompatible 42 41 #include "ScopedSet.h" // for ScopedSet, ScopedSet<>::iter... … … 592 591 // pass size/align for type variables 593 592 for ( TyVarMap::const_iterator tyParm = exprTyVars.begin(); tyParm != exprTyVars.end(); ++tyParm ) { 594 ResolvExpr::EqvClass eqvClass;595 593 assert( env ); 596 594 if ( tyParm->second.isComplete ) { -
src/ResolvExpr/AdjustExprType.cc
r28f3a19 rb21c77a 19 19 #include "SynTree/Mutator.h" // for Mutator 20 20 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type 21 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment21 #include "TypeEnvironment.h" // for ClassRef, TypeEnvironment 22 22 23 23 namespace ResolvExpr { … … 74 74 75 75 Type * AdjustExprType::postmutate( TypeInstType * typeInst ) { 76 if ( const EqvClass*eqvClass = env.lookup( typeInst->get_name() ) ) {77 if ( eqvClass ->data.kind == TypeDecl::Ftype ) {76 if ( ClassRef eqvClass = env.lookup( typeInst->get_name() ) ) { 77 if ( eqvClass.get_bound().data.kind == TypeDecl::Ftype ) { 78 78 return new PointerType{ Type::Qualifiers(), typeInst }; 79 79 } -
src/ResolvExpr/AlternativeFinder.cc
r28f3a19 rb21c77a 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sat May 16 23:52:08 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Feb 17 11:19:39201813 // Update Count : 3 311 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 11 16:40:00 2018 13 // Update Count : 34 14 14 // 15 15 … … 19 19 #include <iostream> // for operator<<, cerr, ostream, endl 20 20 #include <iterator> // for back_insert_iterator, back_inserter 21 #include <limits> // for numeric_limits<int>::max() 21 22 #include <list> // for _List_iterator, list, _List_const_... 22 23 #include <map> // for _Rb_tree_iterator, map, _Rb_tree_c... 23 24 #include <memory> // for allocator_traits<>::value_type 25 #include <tuple> // for tuple 24 26 #include <utility> // for pair 25 27 #include <vector> // for vector … … 244 246 } 245 247 246 void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast) {248 void AlternativeFinder::find( Expression *expr, ResolvMode mode ) { 247 249 PassVisitor<Finder> finder( *this ); 248 250 expr->accept( finder ); 249 if ( failFast && alternatives.empty() ) {251 if ( mode.failFast && alternatives.empty() ) { 250 252 PRINT( 251 253 std::cerr << "No reasonable alternatives for expression " << expr << std::endl; … … 253 255 SemanticError( expr, "No reasonable alternatives for expression " ); 254 256 } 255 if ( prune ) {257 if ( mode.prune ) { 256 258 auto oldsize = alternatives.size(); 257 259 PRINT( … … 261 263 AltList pruned; 262 264 pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) ); 263 if ( failFast && pruned.empty() ) {265 if ( mode.failFast && pruned.empty() ) { 264 266 std::ostringstream stream; 265 267 AltList winners; … … 280 282 } 281 283 // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted 282 for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i) {283 if ( adjust) {284 adjustExprType( i ->expr->get_result(), i->env, indexer );284 if ( mode.adjust ) { 285 for ( Alternative& i : alternatives ) { 286 adjustExprType( i.expr->result, i.env, indexer ); 285 287 } 286 288 } … … 294 296 295 297 void AlternativeFinder::findWithAdjustment( Expression *expr ) { 296 find( expr, true);298 find( expr, ResolvMode::withAdjustment() ); 297 299 } 298 300 299 301 void AlternativeFinder::findWithoutPrune( Expression * expr ) { 300 find( expr, true, false);302 find( expr, ResolvMode::withoutPrune() ); 301 303 } 302 304 303 305 void AlternativeFinder::maybeFind( Expression * expr ) { 304 find( expr, true, true, false);306 find( expr, ResolvMode::withoutFailFast() ); 305 307 } 306 308 … … 452 454 } 453 455 456 #if 0 // cost of assertions accounted for in function creation 454 457 for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) { 455 458 convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env ); 456 459 } 460 #endif 457 461 458 462 return convCost; … … 580 584 } 581 585 586 namespace { 587 /// Information required to defer resolution of an expression 588 struct AssertionPack { 589 SymTab::Indexer::IdData cdata; ///< Satisfying declaration 590 Type* adjType; ///< Satisfying type 591 TypeEnvironment env; ///< Post-unification environment 592 AssertionSet have; ///< Post-unification have-set 593 AssertionSet need; ///< Post-unification need-set 594 OpenVarSet openVars; ///< Post-unification open-var set 595 596 AssertionPack( const SymTab::Indexer::IdData& cdata, Type* adjType, 597 TypeEnvironment&& env, AssertionSet&& have, AssertionSet&& need, 598 OpenVarSet&& openVars ) 599 : cdata(cdata), adjType(adjType), env(std::move(env)), have(std::move(have)), 600 need(std::move(need)), openVars(std::move(openVars)) {} 601 }; 602 603 /// List of deferred assertion resolutions for the same type 604 using DeferList = std::vector<AssertionPack>; 605 606 /// Intermediate state for assertion resolution 607 struct AssertionResnState { 608 using DeferItem = std::tuple<DeclarationWithType*, AssertionSetValue, DeferList>; 609 610 const Alternative& alt; ///< Alternative being built from 611 AssertionSet newNeed; ///< New assertions found from current assertions 612 OpenVarSet openVars; ///< Open variables in current context 613 std::vector<DeferItem> deferred; ///< Possible deferred assertion resolutions 614 const SymTab::Indexer& indexer; ///< Name lookup 615 616 AssertionResnState(const Alternative& alt, const OpenVarSet& openVars, 617 const SymTab::Indexer& indexer ) 618 : alt{alt}, have{}, newNeed{}, openVars{openVars}, indexer{indexer} {} 619 }; 620 621 /// Binds a single assertion from a compatible AssertionPack, updating resolution state 622 /// as appropriate. 623 void bindAssertion( DeclarationWithType* curDecl, AssertionSetValue& assnInfo, 624 AssertionResnState& resn, AssertionPack&& match ) { 625 DeclarationWithType* candidate = match.cdata.id; 626 627 addToIndexer( match.have, resn.indexer ); 628 resn.newNeed.insert( match.need.begin(), match.need.end() ); 629 resn.openVars = std::move(match.openVars); 630 resn.alt.env = std::move(match.env); 631 632 assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() ); 633 for ( auto& a : match.need ) { 634 if ( a.second.idChain.empty() ) { 635 a.second.idChain = assnInfo.idChain; 636 a.second.idChain.push_back( curDecl->get_uniqueId() ); 637 } 638 } 639 640 Expression* varExpr = match.cdata.combine( resn.alt.cvtCost ); 641 varExpr->result = match.adjType; 642 643 // follow the current assertion's ID chain to find the correct set of inferred 644 // parameters to add the candidate o (i.e. the set of inferred parameters belonging 645 // to the entity which requested the assertion parameter) 646 InferredParams* inferParams = &resn.alt.expr->inferParams; 647 for ( UniqueId id : assnInfo.idChain ) { 648 inferParams = (*inferParams)[ id ].inferParams.get(); 649 } 650 651 (*inferParams)[ curDecl->get_uniqueId() ] = ParamEntry{ 652 candidate->get_uniqueId(), match.adjType, curDecl->get_type(), varExpr }; 653 } 654 655 /// Resolves a single assertion, returning false if no satisfying assertion, binding it 656 /// if there is exactly one satisfying assertion, or adding to the defer-list if there 657 /// is more than one 658 bool resolveAssertion( DeclarationWithType* curDecl, AssertionSetValue& assnInfo, 659 AssertionResnState& resn ) { 660 // skip unused assertions 661 if ( ! assnInfo.isUsed ) return true; 662 663 // lookup candidates for this assertion 664 std::list< SymTab::Indexer::IdData > candidates; 665 decls.lookupId( curDecl->name, candidates ); 666 667 // find the ones that unify with the desired type 668 DeferList matches; 669 for ( const auto& cdata : candidates ) { 670 DeclarationWithType* candidate = cdata.id; 671 672 // build independent unification context for candidate 673 AssertionSet have, newNeed; 674 TypeEnvironment newEnv{ resn.alt.env }; 675 OpenVarSet newOpenVars{ resn.openVars }; 676 Type* adjType = candidate->get_type()->clone(); 677 adjustExprType( adjType, newEnv, resn.indexer ); 678 renameTyVars( adjType ); 679 680 if ( unify( curDecl->get_type(), adjType, newEnv, 681 newNeed, have, newOpenVars, resn.indexer ) ) { 682 matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have), 683 std::move(newNeed), std::move(newOpenVars) ); 684 } 685 } 686 687 // Break if no suitable assertion 688 if ( matches.empty() ) return false; 689 690 // Defer if too many suitable assertions 691 if ( matches.size() > 1 ) { 692 resn.deferred.emplace_back( curDecl, assnInfo, std::move(matches) ); 693 return true; 694 } 695 696 // otherwise bind current match in ongoing scope 697 bindAssertion( curDecl, assnInfo, resn, std::move(matches.front()) ); 698 699 return true; 700 } 701 } 702 582 703 template< typename OutputIterator > 583 704 void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) { … … 594 715 // ) 595 716 addToIndexer( have, decls ); 717 718 AssertionResnState resn{ newAlt, openVars, indexer }; 719 720 // resolve assertions in breadth-first-order up to a limited number of levels deep 721 int level; 722 for ( level = 0; level < recursionLimit; ++level ) { 723 // make initial pass at matching assertions 724 for ( auto& assn : need ) { 725 if ( ! resolveAssertion( assn.first, assn.second, resn ) ) { 726 // fail early if any assertion fails to resolve 727 return; 728 } 729 } 730 731 // resolve deferred assertions by mutual compatibility and min-cost 732 if ( ! resn.deferred.empty() ) { 733 // TODO 734 assert(false && "TODO: deferred assertions unimplemented"); 735 736 // reset for next round 737 resn.deferred.clear(); 738 } 739 740 // quit resolving assertions if done 741 if ( resn.newNeed.empty() ) break; 742 743 // otherwise start on next group of recursive assertions 744 need.swap( resn.newNeed ); 745 resn.newNeed.clear(); 746 } 747 if ( level >= recursionLimit ) { 748 SemanticError( newAlt.expr->location, "Too many recursive assertions" ); 749 } 750 751 // add completed assertion to output 752 *out++ = newAlt; 753 754 #if 0 596 755 AssertionSet newNeed; 597 756 PRINT( … … 607 766 // *out++ = newAlt; 608 767 // ) 768 #endif 609 769 } 610 770 … … 640 800 641 801 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 642 const OpenVarSet& openVars )643 : parent(0), expr(nullptr), cost( Cost::zero), env(env), need(need), have(have),802 const OpenVarSet& openVars, Cost initCost = Cost::zero) 803 : parent(0), expr(nullptr), cost(initCost), env(env), need(need), have(have), 644 804 openVars(openVars), nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {} 645 805 … … 933 1093 } 934 1094 1095 namespace { 1096 1097 struct CountSpecs : public WithVisitorRef<CountSpecs>, WithShortCircuiting { 1098 1099 void postvisit(PointerType*) { 1100 // mark specialization of base type 1101 if ( count >= 0 ) ++count; 1102 } 1103 1104 void postvisit(ArrayType*) { 1105 // mark specialization of base type 1106 if ( count >= 0 ) ++count; 1107 } 1108 1109 void postvisit(ReferenceType*) { 1110 // mark specialization of base type -- xxx maybe not? 1111 if ( count >= 0 ) ++count; 1112 } 1113 1114 private: 1115 // takes minimum non-negative count over parameter/return list 1116 void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) { 1117 for ( DeclarationWithType* dwt : dwts ) { 1118 count = -1; 1119 maybeAccept( dwt->get_type(), *visitor ); 1120 if ( count != -1 && count < mincount ) mincount = count; 1121 } 1122 } 1123 1124 public: 1125 void previsit(FunctionType*) { 1126 // override default child visiting behaviour 1127 visit_children = false; 1128 } 1129 1130 void postvisit(FunctionType* fty) { 1131 // take minimal set value of count over ->returnVals and ->parameters 1132 int mincount = std::numeric_limits<int>::max(); 1133 takeminover( mincount, fty->parameters ); 1134 takeminover( mincount, fty->returnVals ); 1135 // add another level to mincount if set 1136 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1; 1137 } 1138 1139 private: 1140 // returns minimum non-negative count + 1 over type parameters (-1 if none such) 1141 int minover( std::list<Expression*>& parms ) { 1142 int mincount = std::numeric_limits<int>::max(); 1143 for ( Expression* parm : parms ) { 1144 count = -1; 1145 maybeAccept( parm->get_result(), *visitor ); 1146 if ( count != -1 && count < mincount ) mincount = count; 1147 } 1148 return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1; 1149 } 1150 1151 public: 1152 void previsit(StructInstType*) { 1153 // override default child behaviour 1154 visit_children = false; 1155 } 1156 1157 void postvisit(StructInstType* sity) { 1158 // look for polymorphic parameters 1159 count = minover( sity->parameters ); 1160 } 1161 1162 void previsit(UnionInstType*) { 1163 // override default child behaviour 1164 visit_children = false; 1165 } 1166 1167 void postvisit(UnionInstType* uity) { 1168 // look for polymorphic parameters 1169 count = minover( uity->parameters ); 1170 } 1171 1172 void postvisit(TypeInstType*) { 1173 // note polymorphic type (which may be specialized) 1174 // xxx - maybe account for open/closed type variables 1175 count = 0; 1176 } 1177 1178 void previsit(TupleType*) { 1179 // override default child behaviour 1180 visit_children = false; 1181 } 1182 1183 void postvisit(TupleType* tty) { 1184 // take minimum non-negative count 1185 int mincount = std::numeric_limits<int>::max(); 1186 for ( Type* ty : tty->types ) { 1187 count = -1; 1188 maybeAccept( ty, *visitor ); 1189 if ( count != -1 && count < mincount ) mincount = count; 1190 } 1191 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize 1192 count = mincount < std::numeric_limits<int>::max() ? mincount + 1: -1; 1193 } 1194 1195 int get_count() const { return count >= 0 ? count : 0; } 1196 private: 1197 int count = -1; 1198 }; 1199 1200 /// Counts the specializations in the types in a function parameter or return list 1201 int countSpecs( std::list<DeclarationWithType*>& dwts ) { 1202 int k = 0; 1203 for ( DeclarationWithType* dwt : dwts ) { 1204 PassVisitor<CountSpecs> counter; 1205 maybeAccept( dwt->get_type(), *counter.pass.visitor ); 1206 k += counter.pass.get_count(); 1207 } 1208 return k; 1209 } 1210 1211 /// Calculates the inherent costs in a function declaration; varCost for the number of 1212 /// type variables and specCost for type assertions, as well as PolyType specializations 1213 /// in the parameter and return lists. 1214 Cost declCost( FunctionType* funcType ) { 1215 Cost k = Cost::zero; 1216 1217 // add cost of type variables 1218 k.incVar( funcType->forall.size() ); 1219 1220 // subtract cost of type assertions 1221 for ( TypeDecl* td : funcType->forall ) { 1222 k.decSpec( td->assertions.size() ); 1223 } 1224 1225 // count specialized polymorphic types in parameter/return lists 1226 k.decSpec( countSpecs( funcType->parameters ) ); 1227 k.decSpec( countSpecs( funcType->returnVals ) ); 1228 1229 return k; 1230 } 1231 } 1232 935 1233 template<typename OutputIterator> 936 1234 void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func, … … 977 1275 } 978 1276 1277 // calculate declaration cost of function (+vars-spec) 1278 Cost funcCost = declCost( funcType ); 1279 979 1280 // iteratively build matches, one parameter at a time 980 1281 std::vector<ArgPack> results; 981 results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } );1282 results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars, funcCost } ); 982 1283 std::size_t genStart = 0; 983 1284 … … 1120 1421 } 1121 1422 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer) 1122 if ( const EqvClass *eqvClass = func->env.lookup( typeInst->name ) ) {1123 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass ->type ) ) {1423 if ( ClassRef eqvClass = func->env.lookup( typeInst->name ) ) { 1424 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.get_bound().type ) ) { 1124 1425 Alternative newFunc( *func ); 1125 1426 referenceToRvalueConversion( newFunc.expr, newFunc.cost ); -
src/ResolvExpr/AlternativeFinder.h
r28f3a19 rb21c77a 22 22 #include "Alternative.h" // for AltList, Alternative 23 23 #include "ExplodedActual.h" // for ExplodedActual 24 #include "ResolvMode.h" // for ResolvMode 24 25 #include "ResolvExpr/Cost.h" // for Cost, Cost::infinity 25 26 #include "ResolvExpr/TypeEnvironment.h" // for AssertionSet, OpenVarSet … … 68 69 } 69 70 70 void find( Expression *expr, bool adjust = false, bool prune = true, bool failFast = true);71 void find( Expression *expr, ResolvMode mode = ResolvMode{} ); 71 72 /// Calls find with the adjust flag set; adjustment turns array and function types into equivalent pointer types 72 73 void findWithAdjustment( Expression *expr ); -
src/ResolvExpr/CastCost.cc
r28f3a19 rb21c77a 18 18 #include "ConversionCost.h" // for ConversionCost 19 19 #include "Cost.h" // for Cost, Cost::infinity 20 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, EqvClass20 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, ClassRef 21 21 #include "SymTab/Indexer.h" // for Indexer 22 22 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl … … 43 43 Cost castCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 44 44 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { 45 if ( const EqvClass*eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {46 if ( eqvClass->type ) {47 return castCost( src, eqvClass->type, indexer, env );45 if ( ClassRef eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 46 if ( Type* boundTy = eqvClass.get_bound().type ) { 47 return castCost( src, boundTy, indexer, env ); 48 48 } else { 49 49 return Cost::infinity; -
src/ResolvExpr/ConversionCost.cc
r28f3a19 rb21c77a 22 22 #include "Common/GC.h" // for new_static_root 23 23 #include "ResolvExpr/Cost.h" // for Cost 24 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment24 #include "ResolvExpr/TypeEnvironment.h" // for ClassRef, TypeEnvironment 25 25 #include "SymTab/Indexer.h" // for Indexer 26 26 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl … … 29 29 30 30 namespace ResolvExpr { 31 const Cost Cost::zero = Cost( 0, 0, 0, 0 ); 32 const Cost Cost::infinity = Cost( -1, -1, -1, -1 ); 33 const Cost Cost::unsafe = Cost( 1, 0, 0, 0 ); 34 const Cost Cost::poly = Cost( 0, 1, 0, 0 ); 35 const Cost Cost::safe = Cost( 0, 0, 1, 0 ); 36 const Cost Cost::reference = Cost( 0, 0, 0, 1 ); 31 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0 }; 32 const Cost Cost::infinity = Cost{ -1, -1, -1, 1, -1, -1 }; 33 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0 }; 34 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0 }; 35 const Cost Cost::var = Cost{ 0, 0, 1, 0, 0, 0 }; 36 const Cost Cost::spec = Cost{ 0, 0, 0, -1, 0, 0 }; 37 const Cost Cost::safe = Cost{ 0, 0, 0, 0, 1, 0 }; 38 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 1 }; 37 39 38 40 #if 0 … … 44 46 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { 45 47 PRINT( std::cerr << "type inst " << destAsTypeInst->name; ) 46 if ( const EqvClass*eqvClass = env.lookup( destAsTypeInst->name ) ) {47 if ( eqvClass->type ) {48 return conversionCost( src, eqvClass->type, indexer, env );48 if ( ClassRef eqvClass = env.lookup( destAsTypeInst->name ) ) { 49 if ( Type* boundTy = eqvClass.get_bound().type ) { 50 return conversionCost( src, boundTy, indexer, env ); 49 51 } else { 50 52 return Cost::infinity; … … 368 370 369 371 void ConversionCost::postvisit( TypeInstType *inst ) { 370 if ( const EqvClass *eqvClass = env.lookup( inst->name ) ) {371 cost = costFunc( eqvClass ->type, dest, indexer, env );372 if ( ClassRef eqvClass = env.lookup( inst->name ) ) { 373 cost = costFunc( eqvClass.get_bound().type, dest, indexer, env ); 372 374 } else if ( TypeInstType *destAsInst = dynamic_cast< TypeInstType* >( dest ) ) { 373 375 if ( inst->name == destAsInst->name ) { -
src/ResolvExpr/Cost.h
r28f3a19 rb21c77a 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 09:39:50 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:35:55 201713 // Update Count : 511 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 11 16:04:00 2018 13 // Update Count : 6 14 14 // 15 15 … … 21 21 class Cost { 22 22 private: 23 Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost );23 Cost( int unsafeCost, int polyCost, int varCost, int specCost, int safeCost, int referenceCost ); 24 24 25 25 public: 26 26 Cost & incUnsafe( int inc = 1 ); 27 27 Cost & incPoly( int inc = 1 ); 28 Cost & incVar( int inc = 1 ); 29 Cost & decSpec( int dec = 1 ); 28 30 Cost & incSafe( int inc = 1 ); 29 31 Cost & incReference( int inc = 1 ); … … 31 33 int get_unsafeCost() const { return unsafeCost; } 32 34 int get_polyCost() const { return polyCost; } 35 int get_varCost() const { return varCost; } 36 int get_specCost() const { return specCost; } 33 37 int get_safeCost() const { return safeCost; } 34 38 int get_referenceCost() const { return referenceCost; } … … 47 51 static const Cost unsafe; 48 52 static const Cost poly; 53 static const Cost var; 54 static const Cost spec; 49 55 static const Cost safe; 50 56 static const Cost reference; 51 57 private: 52 int compare( const Cost &other ) const;53 58 54 int unsafeCost; 55 int polyCost; 56 int safeCost; 57 int referenceCost; 59 int unsafeCost; ///< Unsafe (narrowing) conversions 60 int polyCost; ///< Count of parameters and return values bound to some poly type 61 int varCost; ///< Count of polymorphic type variables 62 int specCost; ///< Polymorphic type specializations (type assertions), negative cost 63 int safeCost; ///< Safe (widening) conversions 64 int referenceCost; ///< reference conversions 58 65 }; 59 66 60 inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost ) : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), referenceCost( referenceCost ) {} 67 inline Cost::Cost( 68 int unsafeCost, int polyCost, int varCost, int specCost, int safeCost, int referenceCost ) : unsafeCost( unsafeCost ), polyCost( polyCost ), varCost( varCost ), specCost( specCost ), 69 safeCost( safeCost ), referenceCost( referenceCost ) {} 61 70 62 71 inline Cost & Cost::incUnsafe( int inc ) { … … 69 78 if ( *this == infinity ) return *this; 70 79 polyCost += inc; 80 return *this; 81 } 82 83 inline Cost & Cost::incVar( int inc ) { 84 if ( *this == infinity ) return *this; 85 varCost += inc; 86 return *this; 87 } 88 89 inline Cost& Cost::decSpec( int dec ) { 90 if ( *this == infinity ) return *this; 91 specCost -= dec; 71 92 return *this; 72 93 } … … 86 107 inline Cost Cost::operator+( const Cost &other ) const { 87 108 if ( *this == infinity || other == infinity ) return infinity; 88 return Cost( unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost, referenceCost + other.referenceCost ); 109 return Cost( 110 unsafeCost + other.unsafeCost, polyCost + other.polyCost, 111 varCost + other.varCost, specCost + other.specCost, 112 safeCost + other.safeCost, referenceCost + other.referenceCost ); 89 113 } 90 114 91 115 inline Cost Cost::operator-( const Cost &other ) const { 92 116 if ( *this == infinity || other == infinity ) return infinity; 93 return Cost( unsafeCost - other.unsafeCost, polyCost - other.polyCost, safeCost - other.safeCost, referenceCost - other.referenceCost ); 117 return Cost( 118 unsafeCost - other.unsafeCost, polyCost - other.polyCost, 119 varCost + other.varCost, specCost + other.specCost, 120 safeCost - other.safeCost, referenceCost - other.referenceCost ); 94 121 } 95 122 … … 102 129 unsafeCost += other.unsafeCost; 103 130 polyCost += other.polyCost; 131 varCost += other.varCost; 132 specCost += other.specCost; 104 133 safeCost += other.safeCost; 105 134 referenceCost += other.referenceCost; … … 119 148 } else if ( polyCost < other.polyCost ) { 120 149 return true; 150 } else if ( varCost > other.varCost ) { 151 return false; 152 } else if ( varCost < other.varCost ) { 153 return true; 154 } else if ( specCost > other.specCost ) { 155 return false; 156 } else if ( specCost < other.specCost ) { 157 return true; 121 158 } else if ( safeCost > other.safeCost ) { 122 159 return false; … … 135 172 return unsafeCost == other.unsafeCost 136 173 && polyCost == other.polyCost 174 && varCost == other.varCost 175 && specCost == other.specCost 137 176 && safeCost == other.safeCost 138 177 && referenceCost == other.referenceCost; … … 144 183 145 184 inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) { 146 os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " << cost.safeCost << ", " << cost.referenceCost << " )"; 147 return os; 185 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " 186 << cost.varCost << ", " << cost.specCost << ", " 187 << cost.safeCost << ", " << cost.referenceCost << " )"; 148 188 } 149 189 } // namespace ResolvExpr -
src/ResolvExpr/Occurs.cc
r28f3a19 rb21c77a 14 14 // 15 15 16 #include <set> // for set, _Rb_tree_const_iterator17 16 #include <string> // for string 17 #include <unordered_set> // for unordered_set 18 18 19 19 #include "Common/PassVisitor.h" 20 20 #include "SynTree/Type.h" // for TypeInstType, Type 21 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment21 #include "TypeEnvironment.h" // for ClassRef, TypeEnvironment 22 22 23 23 namespace ResolvExpr { … … 27 27 28 28 bool result; 29 std::set< std::string > eqvVars; 29 using VarSet = std::unordered_set< std::string >; 30 VarSet eqvVars; 30 31 const TypeEnvironment &tenv; 31 32 }; … … 38 39 39 40 Occurs::Occurs( std::string varName, const TypeEnvironment & env ) : result( false ), tenv( env ) { 40 if ( const EqvClass *eqvClass = tenv.lookup( varName ) ) {41 eqvVars = eqvClass ->vars;41 if ( ClassRef eqvClass = tenv.lookup( varName ) ) { 42 eqvVars = eqvClass.get_vars<VarSet>(); 42 43 } else { 43 44 eqvVars.insert( varName ); … … 51 52 if ( eqvVars.find( typeInst->get_name() ) != eqvVars.end() ) { 52 53 result = true; 53 } else if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {54 if ( eqvClass->type ) {54 } else if ( ClassRef eqvClass = tenv.lookup( typeInst->get_name() ) ) { 55 if ( Type* boundTy = eqvClass.get_bound().type ) { 55 56 /// std::cerr << typeInst->get_name() << " is bound to"; 56 /// eqvClass.type->print( std::cerr );57 /// boundTy->print( std::cerr ); 57 58 /// std::cerr << std::endl; 58 eqvClass->type->accept( *visitor );59 boundTy->accept( *visitor ); 59 60 } // if 60 61 } // if -
src/ResolvExpr/PolyCost.cc
r28f3a19 rb21c77a 17 17 #include "SymTab/Indexer.h" // for Indexer 18 18 #include "SynTree/Type.h" // for TypeInstType, Type 19 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment19 #include "TypeEnvironment.h" // for ClassRef, TypeEnvironment 20 20 21 21 namespace ResolvExpr { … … 39 39 40 40 void PolyCost::previsit(TypeInstType * typeInst) { 41 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) {42 if ( eqvClass->type ) {43 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type) ) {41 if ( ClassRef eqvClass = tenv.lookup( typeInst->name ) ) { 42 if ( Type* boundTy = eqvClass.get_bound().type ) { 43 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( boundTy ) ) { 44 44 if ( indexer.lookupType( otherTypeInst->name ) ) { 45 45 // bound to opaque type -
src/ResolvExpr/PtrsAssignable.cc
r28f3a19 rb21c77a 15 15 16 16 #include "Common/PassVisitor.h" 17 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment17 #include "ResolvExpr/TypeEnvironment.h" // for ClassRef, TypeEnvironment 18 18 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType 19 19 #include "SynTree/Visitor.h" // for Visitor … … 51 51 // std::cerr << "assignable: " << src << " | " << dest << std::endl; 52 52 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { 53 if ( const EqvClass *eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {54 return ptrsAssignable( src, eqvClass ->type, env );53 if ( ClassRef eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 54 return ptrsAssignable( src, eqvClass.get_bound().type, env ); 55 55 } // if 56 56 } // if … … 94 94 void PtrsAssignable::postvisit( __attribute__((unused)) TraitInstType *inst ) {} 95 95 void PtrsAssignable::postvisit( TypeInstType *inst ) { 96 if ( const EqvClass *eqvClass = env.lookup( inst->get_name() ) ) {97 if ( eqvClass->type ) {96 if ( ClassRef eqvClass = env.lookup( inst->get_name() ) ) { 97 if ( Type* boundTy = eqvClass.get_bound().type ) { 98 98 // T * = S * for any S depends on the type bound to T 99 result = ptrsAssignable( eqvClass->type, dest, env );99 result = ptrsAssignable( boundTy, dest, env ); 100 100 } 101 101 } // if -
src/ResolvExpr/PtrsCastable.cc
r28f3a19 rb21c77a 15 15 16 16 #include "Common/PassVisitor.h" 17 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment17 #include "ResolvExpr/TypeEnvironment.h" // for ClassRef, TypeEnvironment 18 18 #include "SymTab/Indexer.h" // for Indexer 19 19 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype … … 63 63 } // if 64 64 } //if 65 } else if ( const EqvClass *eqvClass = env.lookup( typeInst->get_name() ) ) {66 if ( eqvClass ->data.kind == TypeDecl::Ftype ) {65 } else if ( ClassRef eqvClass = env.lookup( typeInst->get_name() ) ) { 66 if ( eqvClass.get_bound().data.kind == TypeDecl::Ftype ) { 67 67 return -1; 68 68 } // if … … 78 78 int ptrsCastable( Type *src, Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) { 79 79 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { 80 if ( const EqvClass *eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {80 if ( ClassRef eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 81 81 // xxx - should this be ptrsCastable? 82 return ptrsAssignable( src, eqvClass ->type, env );82 return ptrsAssignable( src, eqvClass.get_bound().type, env ); 83 83 } // if 84 84 } // if -
src/ResolvExpr/Resolver.cc
r28f3a19 rb21c77a 33 33 #include "ResolveTypeof.h" // for resolveTypeof 34 34 #include "Resolver.h" 35 #include "ResolvMode.h" // for ResolvMode 35 36 #include "SymTab/Autogen.h" // for SizeType 36 37 #include "SymTab/Indexer.h" // for Indexer … … 50 51 namespace ResolvExpr { 51 52 struct Resolver final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver>, public WithShortCircuiting, public WithStmtsToAdd { 53 54 friend void resolve( std::list<Declaration*> ); 55 52 56 Resolver() {} 53 57 Resolver( const SymTab::Indexer & other ) { … … 95 99 CurrentObject currentObject = nullptr; 96 100 bool inEnumDecl = false; 101 bool atTopLevel = false; ///< Was this resolver set up at the top level of resolution 97 102 }; 98 103 99 104 void resolve( std::list< Declaration * > translationUnit ) { 100 105 PassVisitor<Resolver> resolver; 106 resolver.pass.atTopLevel = true; // mark resolver as top-level 101 107 acceptAll( translationUnit, resolver ); 102 108 } … … 165 171 166 172 namespace { 167 void findUnfinishedKindExpression( Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {173 void findUnfinishedKindExpression( Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) { 168 174 assertf( untyped, "expected a non-null expression." ); 169 175 … … 172 178 TypeEnvironment env; 173 179 AlternativeFinder finder( indexer, env ); 174 finder.find( untyped, adjust, prune, failFast);180 finder.find( untyped, mode ); 175 181 176 182 #if 0 … … 218 224 219 225 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages 220 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {226 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) { 221 227 if ( ! untyped ) return; 222 228 Alternative choice; 223 findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, adjust, prune, failFast);229 findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode ); 224 230 finishExpr( choice.expr, choice.env, untyped->env ); 225 231 untyped = choice.expr; … … 250 256 // set up and resolve expression cast to void 251 257 Alternative choice; 252 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, true);258 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() ); 253 259 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr ); 254 260 env = std::move( choice.env ); -
src/ResolvExpr/TypeEnvironment.cc
r28f3a19 rb21c77a 7 7 // TypeEnvironment.cc -- 8 8 // 9 // Author : Richard C. Bilson9 // Author : Aaron B. Moss 10 10 // Created On : Sun May 17 12:19:47 2015 11 11 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 18 11:58:00 201813 // Update Count : 412 // Last Modified On : Fri Jun 29 15:51:00 2018 13 // Update Count : 5 14 14 // 15 15 … … 19 19 #include <utility> // for pair, move 20 20 21 #include "Common/InternedString.h" // for interned_string 21 22 #include "Common/PassVisitor.h" // for PassVisitor<GcTracer> 22 23 #include "Common/utility.h" // for maybeClone 24 #include "SymTab/Indexer.h" // for Indexer 23 25 #include "SynTree/GcTracer.h" // for PassVisitor<GcTracer> 24 26 #include "SynTree/Type.h" // for Type, FunctionType, Type::Fora... 25 27 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 26 #include "Tuples/Tuples.h" // for isTtype27 28 #include "TypeEnvironment.h" 28 29 #include "typeops.h" // for occurs … … 48 49 } 49 50 51 #if 0 50 52 void EqvClass::initialize( const EqvClass &src, EqvClass &dest ) { 51 53 initialize( src, dest, src.type ); … … 115 117 return nullptr; 116 118 } 117 118 /// Removes any class from env that intersects eqvClass 119 void filterOverlappingClasses( std::list<EqvClass> &env, const EqvClass &eqvClass ) { 120 for ( auto i = env.begin(); i != env.end(); ) { 121 auto next = i; 122 ++next; 123 std::set<std::string> intersection; 124 std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 125 std::inserter( intersection, intersection.begin() ) ); 126 if ( ! intersection.empty() ) { env.erase( i ); } 127 i = next; 128 } 129 } 130 131 void TypeEnvironment::add( EqvClass &&eqvClass ) { 132 filterOverlappingClasses( env, eqvClass ); 133 env.push_back( std::move(eqvClass) ); 134 } 135 136 void TypeEnvironment::add( const Type::ForallList &tyDecls ) { 137 for ( Type::ForallList::const_iterator i = tyDecls.begin(); i != tyDecls.end(); ++i ) { 138 EqvClass newClass; 139 newClass.vars.insert( (*i)->get_name() ); 140 newClass.data = TypeDecl::Data{ (*i) }; 141 env.push_back( std::move(newClass) ); 142 } // for 143 } 144 145 void TypeEnvironment::add( const TypeSubstitution & sub ) { 146 EqvClass newClass; 147 for ( auto p : sub ) { 148 newClass.vars.insert( p.first ); 149 newClass.type = p.second->clone(); 150 newClass.allowWidening = false; 151 // Minimal assumptions. Not technically correct, but might be good enough, and 152 // is the best we can do at the moment since information is lost in the 153 // transition to TypeSubstitution 154 newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false }; 155 add( std::move(newClass) ); 156 } 157 } 158 159 void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const { 160 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) { 161 for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) { 162 if ( theClass->type ) { 163 sub.add( *theVar, theClass->type ); 164 } else if ( theVar != theClass->vars.begin() ) { 165 TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype ); 166 sub.add( *theVar, newTypeInst ); 167 } // if 168 } // for 169 } // for 170 sub.normalize(); 171 } 172 173 void TypeEnvironment::print( std::ostream &os, Indenter indent ) const { 174 for ( const EqvClass & theClass : env ) { 175 theClass.print( os, indent ); 176 } // for 177 } 178 179 std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) { 180 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) { 181 if ( i->vars.count( var ) ) return i; 182 } // for 183 return env.end(); 184 } 185 186 void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) { 187 env.insert( env.end(), second.env.begin(), second.env.end() ); 188 } 189 190 void TypeEnvironment::extractOpenVars( OpenVarSet &openVars ) const { 191 for ( std::list< EqvClass >::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) { 192 for ( std::set< std::string >::const_iterator var = eqvClass->vars.begin(); var != eqvClass->vars.end(); ++var ) { 193 openVars[ *var ] = eqvClass->data; 194 } // for 195 } // for 196 } 197 198 void TypeEnvironment::addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ) { 199 for ( const EqvClass& c : actualEnv ) { 200 EqvClass c2 = c; 201 c2.allowWidening = false; 202 for ( const std::string& var : c2.vars ) { 203 openVars[ var ] = c2.data; 204 } 205 env.push_back( std::move(c2) ); 206 } 119 #endif 120 121 std::pair<interned_string, interned_string> TypeEnvironment::mergeClasses( 122 interned_string root1, interned_string root2 ) { 123 // merge classes 124 Classes* newClasses = classes->merge( root1, root2 ); 125 126 // determine new root 127 assertf(classes->get_mode() == Classes::REMFROM, "classes updated to REMFROM by merge"); 128 auto ret = std::make_pair( classes->get_root(), classes->get_child ); 129 130 // finalize classes 131 classes = newClasses; 132 return ret; 133 } 134 135 ClassRef TypeEnvironment::lookup( interned_string var ) const { 136 interned_string root = classes->find_or_default( var, nullptr ); 137 if ( root ) return { this, root }; 138 else return { nullptr, var }; 207 139 } 208 140 … … 233 165 } 234 166 235 bool TypeEnvironment::bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 236 167 bool TypeEnvironment::bindVar( TypeInstType* typeInst, Type* bindTo, 168 const TypeDecl::Data& data, AssertionSet& need, AssertionSet& have, 169 const OpenVarSet& openVars, WidenMode widenMode, const SymTab::Indexer& indexer ) { 237 170 // remove references from other, so that type variables can only bind to value types 238 171 bindTo = bindTo->stripReferences(); 239 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );240 a ssert( tyvar != openVars.end() );241 if ( ! tyVarCompatible( tyvar->second, bindTo ) ) {242 243 } // if 244 if ( occurs( bindTo, typeInst->get_name(), *this ) ) {245 return false; 246 } // if247 auto curClass = internal_lookup( typeInst->get_name());248 if ( curClass != env.end()) {249 if ( curClass->type ) {250 Type *common = 0;251 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to252 Type *newType = curClass->type->clone();172 173 auto tyVar = openVars.find( typeInst->get_name() ); 174 assert( tyVar != openVars.end() ); 175 if ( ! tyVarCompatible( tyVar->second, other ) ) return false; 176 177 if ( occurs( bindTo, typeInst->get_name(), *this ) ) return false; 178 179 if ( ClassRef curClass = lookup( typeInst->get_name() ) ) { 180 BoundType curData = curClass.get_bound(); 181 if ( curData.type ) { 182 Type* common = nullptr; 183 // attempt to unify equivalence class type (which needs its qualifiers restored) 184 // with the target type 185 Type* newType = curData.type->clone(); 253 186 newType->get_qualifiers() = typeInst->get_qualifiers(); 254 if ( unifyInexact( newType, bindTo, *this, need, have, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) { 187 if ( unifyInexact( newType, bindTo, *this, need, have, openVars, 188 widenMode & WidenMode{ curData.allowWidening, true }, indexer, common ) ) { 255 189 if ( common ) { 190 // update bound type to common type 256 191 common->get_qualifiers() = Type::Qualifiers{}; 257 curClass->set_type( common ); 258 } // if 192 curData.type = common; 193 bindings = bindings->set( curClass.update_root(), curData ); 194 } 195 return true; 259 196 } else return false; 260 197 } else { 261 Type* newType = bindTo->clone(); 262 newType->get_qualifiers() = Type::Qualifiers{}; 263 curClass->set_type( newType ); 264 curClass->allowWidening = widenMode.widenFirst && widenMode.widenSecond; 265 } // if 198 // update bound type to other type 199 curData.type = bindTo->clone(); 200 curData.type->get_qualifiers() = Type::Qualifiers{}; 201 curData.allowWidening = widenMode.widenFirst && widenMode.widenSecond; 202 bindings = bindings->set( curClass.get_root(), curData ); 203 } 266 204 } else { 267 EqvClass newClass; 268 newClass.vars.insert( typeInst->get_name() ); 269 newClass.type = bindTo->clone(); 270 newClass.type->get_qualifiers() = Type::Qualifiers(); 271 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond; 272 newClass.data = data; 273 env.push_back( std::move(newClass) ); 274 } // if 205 // make new class consisting entirely of this variable 206 BoundType curData{ bindTo->clone(), widenMode.first && widenMode.second, data }; 207 curData.type->get_qualifiers() = Type::Qualifiers{}; 208 classes = classes->add( curClass.get_root() ); 209 bindings = bindings->set( curClass.get_root(), curData ); 210 } 275 211 return true; 276 212 } 277 278 bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 279 280 auto class1 = internal_lookup( var1->get_name() ); 281 auto class2 = internal_lookup( var2->get_name() ); 213 214 bool TypeEnvironment::bindVarToVar( TypeInstType* var1, TypeInstType* var2, 215 const TypeDecl::Data& data, AssertionSet& need, AssertionSet& have, 216 const OpenVarSet& openVars, WidenMode widenMode, const SymTab::Indexer& indexer ) { 217 ClassRef class1 = env.lookup( var1->get_name() ); 218 ClassRef class2 = env.lookup( var2->get_name() ); 282 219 283 220 // exit early if variables already bound together 284 if ( class1 != env.end() && class1 == class2 ) { 285 class1->allowWidening &= widenMode; 221 if ( class1 && class2 && class1 == class2 ) { 222 BoundType data1 = class1.get_bound(); 223 // narrow the binding if needed 224 if ( data1.allowWidening && widenMode.first != widenMode.second ) { 225 data1.allowWidening = false; 226 bindings = bindings->set( class1.get_root(), data1 ); 227 } 286 228 return true; 287 229 } 288 230 289 bool widen1 = false, widen2 = false; 290 const Type *type1 = nullptr, *type2 = nullptr; 291 292 // check for existing bindings, perform occurs check 293 if ( class1 != env.end() ) { 294 if ( class1->type ) { 295 if ( occurs( class1->type, var2->get_name(), *this ) ) return false; 296 type1 = class1->type; 297 } // if 298 widen1 = widenMode.widenFirst && class1->allowWidening; 299 } // if 300 if ( class2 != env.end() ) { 301 if ( class2->type ) { 302 if ( occurs( class2->type, var1->get_name(), *this ) ) return false; 303 type2 = class2->type; 304 } // if 305 widen2 = widenMode.widenSecond && class2->allowWidening; 306 } // if 307 308 if ( type1 && type2 ) { 309 // both classes bound, merge if bound types can be unified 310 Type *newType1 = type1->clone(), *newType2 = type2->clone(); 311 WidenMode newWidenMode{ widen1, widen2 }; 312 Type *common = 0; 313 if ( unifyInexact( newType1, newType2, *this, need, have, openVars, newWidenMode, indexer, common ) ) { 314 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 315 class1->allowWidening = widen1 && widen2; 231 BoundType data1 = class1 ? class1.get_bound() : BoundType{}; 232 BoundType data2 = class2 ? class2.get_bound() : BoundType{}; 233 234 bool widen1 = data1.allowWidening && widenMode.widenFirst; 235 bool widen2 = data2.allowWidening && widenMode.widenSecond; 236 237 if ( data1.type && data2.type ) { 238 // attempt to unify bound classes 239 Type* common = nullptr; 240 if ( unifyInexact( data1.type->clone(), data2.type->clone(), *this, need, have, 241 openVars, WidenMode{ widen1, widen2 }, indexer, common ) ) { 242 // merge type variables 243 interned_string root = mergeClasses( class1.update_root(), class2.update_root() ); 244 // update bindings 245 data1.allowWidening = widen1 && widen2; 316 246 if ( common ) { 317 247 common->get_qualifiers() = Type::Qualifiers{}; 318 class1->set_type( common );248 data1.type = common; 319 249 } 320 env.erase( class2);250 bindings = bindings->set( root, data1 ); 321 251 } else return false; 322 } else if ( class1 != env.end() && class2 != env.end() ) { 323 // both classes exist, at least one unbound, merge unconditionally 324 if ( type1 ) { 325 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 326 class1->allowWidening = widen1; 327 env.erase( class2 ); 328 } else { 329 class2->vars.insert( class1->vars.begin(), class1->vars.end() ); 330 class2->allowWidening = widen2; 331 env.erase( class1 ); 332 } // if 333 } else if ( class1 != env.end() ) { 334 // var2 unbound, add to class1 335 class1->vars.insert( var2->get_name() ); 336 class1->allowWidening = widen1; 337 } else if ( class2 != env.end() ) { 338 // var1 unbound, add to class2 339 class2->vars.insert( var1->get_name() ); 340 class2->allowWidening = widen2; 252 } else if ( class1 && class2 ) { 253 // both classes exist, only one bound -- merge type variables 254 auto merged = mergeClasses( class1.get_root(), class2.get_root() ); 255 // remove subordinate binding 256 bindings = bindings->erase( merged.second ); 257 // update root binding (narrow widening as needed, or set new binding for changed root) 258 if ( data1.type ) { 259 if ( data1.allowWidening != widen1 ) { 260 data1.allowWidening = widen1; 261 bindings = bindings->set( merged.first, data1 ); 262 } else if ( merged.first == class2.get_root() ) { 263 bindings = bindings->set( merged.first, data1 ); 264 } 265 } else /* if ( data2.type ) */ { 266 if ( data2.allowWidening != widen2 ) { 267 data2.allowWidening = widen2; 268 bindings = bindings->set( root, data2 ); 269 } else if ( merged.first == class1.get_root() ) { 270 bindings = bindings->set( merged.first, data2 ); 271 } 272 } 273 } else if ( class1 ) { 274 // add unbound var2 to class1 275 classes = classes->add( class2.get_root() ); 276 auto merged = mergeClasses( class1.get_root(), class2.get_root() ); 277 // update bindings (narrow as needed, or switch binding to root) 278 if ( merged.first == class2.get_root() ) { 279 data1.allowWidening = widen1; 280 bindings = bindings->erase( merged.second )->set( merged.first, data1 ); 281 } else if ( data1.allowWidening != widen1 ) { 282 bindings = bindings->set( merged.first, data1 ); 283 } 284 } else if ( class2 ) { 285 // add unbound var1 to class1 286 classes = classes->add( class1.get_root() ); 287 auto merged = mergeClasses( class1.get_root(), class2.get_root() ); 288 // update bindings (narrow as needed, or switch binding to root) 289 if ( merged.first == class1.get_root() ) { 290 data2.allowWidening = widen2; 291 bindings = bindings->erase( merged.second )->set( merged.first, data2 ); 292 } else if ( data2.allowWidening != widen2 ) { 293 bindings = bindings->set( merged.first, data2 ); 294 } 341 295 } else { 342 // neither var bound, create new class 296 // make new class with pair of unbound vars 297 classes = classes->add( class1.get_root() )->add( class2.get_root() ); 298 auto merged = mergeClasses( class1.get_root(), class2.get_root() ); 299 bindings = bindings->set( merged.first, BoundType{ nullptr, widen1 && widen2, data } ); 300 } 301 return true; 302 } 303 304 #if !1 305 /// Removes any class from env that intersects eqvClass 306 void filterOverlappingClasses( std::list<EqvClass> &env, const EqvClass &eqvClass ) { 307 for ( auto i = env.begin(); i != env.end(); ) { 308 auto next = i; 309 ++next; 310 std::set<std::string> intersection; 311 std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 312 std::inserter( intersection, intersection.begin() ) ); 313 if ( ! intersection.empty() ) { env.erase( i ); } 314 i = next; 315 } 316 } 317 318 void TypeEnvironment::add( EqvClass &&eqvClass ) { 319 filterOverlappingClasses( env, eqvClass ); 320 env.push_back( std::move(eqvClass) ); 321 } 322 323 void TypeEnvironment::add( const Type::ForallList &tyDecls ) { 324 for ( Type::ForallList::const_iterator i = tyDecls.begin(); i != tyDecls.end(); ++i ) { 343 325 EqvClass newClass; 344 newClass.vars.insert( var1->get_name() ); 345 newClass.vars.insert( var2->get_name() ); 346 newClass.allowWidening = widen1 && widen2; 347 newClass.data = data; 326 newClass.vars.insert( (*i)->get_name() ); 327 newClass.data = TypeDecl::Data{ (*i) }; 348 328 env.push_back( std::move(newClass) ); 349 } // if 350 return true; 351 } 352 353 void TypeEnvironment::forbidWidening() { 354 for ( EqvClass& c : env ) c.allowWidening = false; 329 } // for 330 } 331 332 void TypeEnvironment::add( const TypeSubstitution & sub ) { 333 EqvClass newClass; 334 for ( auto p : sub ) { 335 newClass.vars.insert( p.first ); 336 newClass.type = p.second->clone(); 337 newClass.allowWidening = false; 338 // Minimal assumptions. Not technically correct, but might be good enough, and 339 // is the best we can do at the moment since information is lost in the 340 // transition to TypeSubstitution 341 newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false }; 342 add( std::move(newClass) ); 343 } 344 } 345 346 void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const { 347 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) { 348 for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) { 349 if ( theClass->type ) { 350 sub.add( *theVar, theClass->type ); 351 } else if ( theVar != theClass->vars.begin() ) { 352 TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype ); 353 sub.add( *theVar, newTypeInst ); 354 } // if 355 } // for 356 } // for 357 sub.normalize(); 358 } 359 360 void TypeEnvironment::print( std::ostream &os, Indenter indent ) const { 361 for ( const EqvClass & theClass : env ) { 362 theClass.print( os, indent ); 363 } // for 364 } 365 366 std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) { 367 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) { 368 if ( i->vars.count( var ) ) return i; 369 } // for 370 return env.end(); 371 } 372 373 void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) { 374 env.insert( env.end(), second.env.begin(), second.env.end() ); 375 } 376 377 void TypeEnvironment::extractOpenVars( OpenVarSet &openVars ) const { 378 for ( std::list< EqvClass >::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) { 379 for ( std::set< std::string >::const_iterator var = eqvClass->vars.begin(); var != eqvClass->vars.end(); ++var ) { 380 openVars[ *var ] = eqvClass->data; 381 } // for 382 } // for 383 } 384 385 void TypeEnvironment::addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ) { 386 for ( const EqvClass& c : actualEnv ) { 387 EqvClass c2 = c; 388 c2.allowWidening = false; 389 for ( const std::string& var : c2.vars ) { 390 openVars[ var ] = c2.data; 391 } 392 env.push_back( std::move(c2) ); 393 } 355 394 } 356 395 … … 359 398 return out; 360 399 } 400 #endif 361 401 362 402 PassVisitor<GcTracer> & operator<<( PassVisitor<GcTracer> & gc, const TypeEnvironment & env ) { 363 for ( const EqvClass &c : env ) {364 maybeAccept( c. type, gc );403 for ( ClassRef c : env ) { 404 maybeAccept( c.get_bound().type, gc ); 365 405 } 366 406 return gc; -
src/ResolvExpr/TypeEnvironment.h
r28f3a19 rb21c77a 7 7 // TypeEnvironment.h -- 8 8 // 9 // Author : Richard C. Bilson9 // Author : Aaron B. Moss 10 10 // Created On : Sun May 17 12:24:58 2015 11 11 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 18 11:58:00 201813 // Update Count : 412 // Last Modified On : Fri Jun 29 16:00:00 2018 13 // Update Count : 5 14 14 // 15 15 16 16 #pragma once 17 17 18 #include <iostream> // for ostream 19 #include <list> // for list, list<>::iterator, list<>... 20 #include <map> // for map, map<>::value_compare 21 #include <set> // for set 22 #include <string> // for string 23 #include <utility> // for move, swap 18 #include <iostream> // for ostream 19 #include <iterator> 20 #include <list> // for list, list<>::iterator, list<>... 21 #include <map> // for map, map<>::value_compare 22 #include <set> // for set 23 #include <string> // for string 24 #include <utility> // for pair 25 #include <vector> // for vector 24 26 25 27 #include "WidenMode.h" // for WidenMode 26 28 27 #include "SynTree/Declaration.h" // for TypeDecl::Data, DeclarationWit... 28 #include "SynTree/SynTree.h" // for UniqueId 29 #include "SynTree/Type.h" // for Type, Type::ForallList 30 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 31 32 template< typename Pass > 33 class PassVisitor; 29 #include "Common/InternedString.h" // for interned_string 30 #include "Common/PersistentDisjointSet.h" // for PersistentDisjointSet 31 #include "Common/PersistentMap.h" // for PersistentMap 32 #include "SynTree/Declaration.h" // for TypeDecl::Data, DeclarationWit... 33 #include "SynTree/SynTree.h" // for UniqueId 34 #include "SynTree/Type.h" // for Type, TypeInstType, Type::ForallList 35 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 36 37 template< typename Pass > class PassVisitor; 34 38 class GcTracer; 39 namespace SymTab { class Indexer; } 35 40 36 41 namespace ResolvExpr { … … 43 48 // declarations. 44 49 // 45 // I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this comparator. 50 // I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 51 // comparator. 46 52 // 47 53 // Note: since this compares pointers for position, minor changes in the source file that affect 48 54 // memory layout can alter compilation time in unpredictable ways. For example, the placement 49 55 // of a line directive can reorder type pointers with respect to each other so that assertions 50 // are seen in different orders, causing a potentially different number of unification calls when 51 // resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering line directives 52 // alone, so it would be nice to fix this comparison so that assertions compare more consistently. 53 // I've tried to modify this to compare on mangle name instead of type as the second comparator, but 54 // this causes some assertions to never be recorded. More investigation is needed. 56 // are seen in different orders, causing a potentially different number of unification calls 57 // when resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering 58 // line directives alone, so it would be nice to fix this comparison so that assertions compare 59 // more consistently. I've tried to modify this to compare on mangle name instead of type as 60 // the second comparator, but this causes some assertions to never be recorded. More 61 // investigation is needed. 55 62 struct AssertCompare { 56 63 bool operator()( DeclarationWithType * d1, DeclarationWithType * d2 ) const { … … 62 69 struct AssertionSetValue { 63 70 bool isUsed; 64 // chain of Unique IDs of the assertion declarations. The first ID in the chain is the ID of an assertion on the current type, 65 // with each successive ID being the ID of an assertion pulled in by the previous ID. The last ID in the chain is 66 // the ID of the assertion that pulled in the current assertion. 71 // chain of Unique IDs of the assertion declarations. The first ID in the chain is the ID 72 // of an assertion on the current type, with each successive ID being the ID of an 73 // assertion pulled in by the previous ID. The last ID in the chain is the ID of the 74 // assertion that pulled in the current assertion. 67 75 std::list< UniqueId > idChain; 68 76 }; … … 73 81 void printOpenVarSet( const OpenVarSet &, std::ostream &, int indent = 0 ); 74 82 83 /// A data structure for holding all the necessary information for a type binding 84 struct BoundType { 85 Type* type; 86 bool allowWidening; 87 TypeDecl::Data data; 88 }; 89 90 #if 0 91 /// An equivalence class, with its binding information 75 92 struct EqvClass { 76 93 std::set< std::string > vars; … … 92 109 void set_type(Type* ty); 93 110 }; 111 #endif 112 113 class TypeEnvironment; 114 115 /// A reference to an equivalence class that may be used to constitute one from its environment 116 class ClassRef { 117 friend TypeEnvironment; 118 119 const TypeEnvironment* env; ///< Containing environment 120 interned_string root; ///< Name of root type 121 122 public: 123 ClassRef() : env(nullptr), root(nullptr) {} 124 ClassRef( const TypeEnvironment* env, interned_string root ) : env(env), root(root) {} 125 126 /// Gets the root of the reference equivalence class; 127 interned_string get_root() const { return root; } 128 129 /// Ensures that root is still the representative element of this typeclass; 130 /// undefined behaviour if called without referenced typeclass; returns new root 131 inline interned_string update_root(); 132 133 /// Gets the type variables of the referenced equivalence class, empty list for none 134 template<typename T = std::vector<interned_string>> 135 inline T get_vars() const; 136 137 /// Gets the bound type information of the referenced equivalence class, default if none 138 inline BoundType get_bound() const; 139 140 #if 0 141 /// Gets the referenced equivalence class 142 inline EqvClass get_class() const; 143 EqvClass operator* () const { return get_class(); } 144 #endif 145 146 // Check that there is a referenced typeclass 147 explicit operator bool() const { return env != nullptr; } 148 149 bool operator== (const ClassRef& o) const { return env == o.env && root == o.root; } 150 bool operator!= (const ClassRef& o) const { return !(*this == o); } 151 }; 94 152 95 153 class TypeEnvironment { 154 friend ClassRef; 155 156 /// Backing storage for equivalence classes 157 using Classes = PersistentDisjointSet<interned_string>; 158 /// Type bindings included in this environment (from class root) 159 using Bindings = PersistentMap<interned_string, BoundType>; 160 161 /// Sets of equivalent type variables, stored by name 162 Classes* classes; 163 /// Bindings from roots of equivalence classes to type binding information. 164 /// All roots have a binding so that the list of classes can be reconstituted, though these 165 /// may be null. 166 Bindings* bindings; 167 168 /// Merges the classes rooted at root1 and root2, returning a pair containing the root and 169 /// child of the bound class. Does not check for validity of merge. 170 std::pair<interned_string, interned_string> mergeClasses( 171 interned_string root1, interned_string root2 ); 172 96 173 public: 97 const EqvClass* lookup( const std::string &var ) const; 98 private: 99 void add( EqvClass &&eqvClass ); 100 public: 174 class iterator : public std::iterator< 175 std::forward_iterator_tag, 176 ClassRef, 177 std::iterator_traits<Bindings::iterator>::difference_type, 178 ClassRef, 179 ClassRef> { 180 friend TypeEnvironment; 181 182 const TypeEnvironment* env; 183 Bindings::iterator it; 184 185 iterator(const TypeEnvironment* e, Bindings::iterator&& i) : env(e), it(std::move(i)) {} 186 187 ClassRef ref() const { return { env, it->first }; } 188 public: 189 iterator() = default; 190 191 reference operator* () { return ref(); } 192 pointer operator-> () { return ref(); } 193 194 iterator& operator++ () { ++it; return *this; } 195 iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; } 196 197 bool operator== (const iterator& o) const { return env == o.env && it == o.it; } 198 bool operator!= (const iterator& o) const { return !(*this == o); } 199 }; 200 201 /// Finds a reference to the class containing `var`, invalid if none such. 202 /// returned root variable will be valid regardless 203 ClassRef lookup( interned_string var ) const; 204 ClassRef lookup( const std::string &var ) const { return lookup( var ); } 205 206 /// Binds a type variable to a type; returns false if fails 207 bool bindVar( TypeInstType* typeInst, Type* bindTo, const TypeDecl::Data& data, 208 AssertionSet& need, AssertionSet& have, const OpenVarSet& openVars, 209 WidenMode widenMode, const SymTab::Indexer& indexer ); 210 211 /// Binds two type variables together; returns false if fails 212 bool bindVarToVar( TypeInstType* var1, TypeInstType* var2, const TypeDecl::Data& data, 213 AssertionSet& need, AssertionSet& have, const OpenVarSet& openVars, 214 WidenMode widenMode, const SymTab::Indexer& indexer ); 215 #if !1 216 private: 217 void add( EqvClass &&eqvClass ); 218 public: 101 219 void add( const Type::ForallList &tyDecls ); 102 220 void add( const TypeSubstitution & sub ); … … 104 222 template< typename SynTreeClass > int applyFree( SynTreeClass *&type ) const; 105 223 void makeSubstitution( TypeSubstitution &result ) const; 106 bool isEmpty() const { return env.empty(); } 224 #endif 225 bool isEmpty() const { return classes->empty(); } 226 #if !1 107 227 void print( std::ostream &os, Indenter indent = {} ) const; 108 // void combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) );109 228 void simpleCombine( const TypeEnvironment &second ); 110 229 void extractOpenVars( OpenVarSet &openVars ) const; 230 #endif 111 231 TypeEnvironment *clone() const { return new TypeEnvironment( *this ); } 112 232 233 #if !1 113 234 /// Iteratively adds the environment of a new actual (with allowWidening = false), 114 235 /// and extracts open variables. 115 236 void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ); 116 237 117 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add118 /// the class if needed. Returns false on failure.119 bool bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );120 121 /// Binds the type classes represented by `var1` and `var2` together; will add122 /// one or both classes if needed. Returns false on failure.123 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );124 125 238 /// Disallows widening for all bindings in the environment 126 239 void forbidWidening(); 127 128 using iterator = std::list< EqvClass >::const_iterator; 129 iterator begin() const { return env.begin(); } 130 iterator end() const { return env.end(); } 131 132 private: 133 std::list< EqvClass > env; 134 135 std::list< EqvClass >::iterator internal_lookup( const std::string &var ); 136 }; 240 #endif 241 242 iterator begin() { return { this, bindings->begin() }; } 243 iterator end() { return { this, bindings->end() }; } 244 }; 245 246 void ClassRef::update_root() { return root = env->classes->find( root ); } 247 248 template<typename T> 249 T ClassRef::get_vars() const { 250 T vars; 251 env->classes->find_class( root, std::inserter(vars, vars.end()) ); 252 return vars; 253 } 254 255 BoundType ClassRef::get_bound() const { 256 return env->bindings->get_or_default( root, BoundType{} ); 257 } 258 259 #if 0 260 EqvClass ClassRef::get_class() const { return { get_vars(), get_bound() }; } 261 #endif 137 262 138 263 template< typename SynTreeClass > … … 150 275 } 151 276 277 #if !1 152 278 std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ); 279 #endif 153 280 154 281 PassVisitor<GcTracer> & operator<<( PassVisitor<GcTracer> & gc, const TypeEnvironment & env ); -
src/ResolvExpr/Unify.cc
r28f3a19 rb21c77a 31 31 #include "SynTree/Visitor.h" // for Visitor 32 32 #include "Tuples/Tuples.h" // for isTtype 33 #include "TypeEnvironment.h" // for EqvClass, AssertionSet, OpenVarSet33 #include "TypeEnvironment.h" // for ClassRef, AssertionSet, OpenVarSet 34 34 #include "Unify.h" 35 35 #include "typeops.h" // for flatten, occurs, commonType … … 377 377 void premutate( TypeInstType * ) { visit_children = false; } 378 378 Type * postmutate( TypeInstType * typeInst ) { 379 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {379 if ( ClassRef eqvClass = tenv.lookup( typeInst->get_name() ) ) { 380 380 // expand ttype parameter into its actual type 381 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) { 382 return eqvClass->type->clone(); 381 BoundType cBound = eqvClass.get_bound(); 382 if ( cBound.data.kind == TypeDecl::Ttype && cBound.type ) { 383 return cBound.type->clone(); 383 384 } 384 385 }
Note:
See TracChangeset
for help on using the changeset viewer.