Changeset 90152a4 for src/ResolvExpr/TypeEnvironment.cc
- Timestamp:
- Aug 27, 2018, 4:40:34 PM (7 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- b7c89aa
- Parents:
- f9feab8 (diff), 305581d (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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/TypeEnvironment.cc
rf9feab8 r90152a4 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:19:47 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun May 17 12:23:36 201513 // Update Count : 311 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 18 11:58:00 2018 13 // Update Count : 4 14 14 // 15 15 … … 17 17 #include <algorithm> // for copy, set_intersection 18 18 #include <iterator> // for ostream_iterator, insert_iterator 19 #include <utility> // for pair 19 #include <memory> // for unique_ptr 20 #include <utility> // for pair, move 20 21 21 22 #include "Common/utility.h" // for maybeClone 22 23 #include "SynTree/Type.h" // for Type, FunctionType, Type::Fora... 23 24 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 25 #include "Tuples/Tuples.h" // for isTtype 24 26 #include "TypeEnvironment.h" 27 #include "typeops.h" // for occurs 28 #include "Unify.h" // for unifyInexact 25 29 26 30 namespace ResolvExpr { … … 44 48 45 49 void EqvClass::initialize( const EqvClass &src, EqvClass &dest ) { 50 initialize( src, dest, src.type ); 51 } 52 53 void EqvClass::initialize( const EqvClass &src, EqvClass &dest, const Type *ty ) { 46 54 dest.vars = src.vars; 47 dest.type = maybeClone( src.type);55 dest.type = maybeClone( ty ); 48 56 dest.allowWidening = src.allowWidening; 49 57 dest.data = src.data; 50 58 } 51 59 52 EqvClass::EqvClass() : type( 0), allowWidening( true ) {60 EqvClass::EqvClass() : type( nullptr ), allowWidening( true ) { 53 61 } 54 62 55 63 EqvClass::EqvClass( const EqvClass &other ) { 56 64 initialize( other, *this ); 65 } 66 67 EqvClass::EqvClass( const EqvClass &other, const Type *ty ) { 68 initialize( other, *this, ty ); 69 } 70 71 EqvClass::EqvClass( EqvClass &&other ) 72 : vars{std::move(other.vars)}, type{other.type}, 73 allowWidening{std::move(other.allowWidening)}, data{std::move(other.data)} { 74 other.type = nullptr; 57 75 } 58 76 … … 64 82 } 65 83 84 EqvClass &EqvClass::operator=( EqvClass &&other ) { 85 if ( this == &other ) return *this; 86 delete type; 87 88 vars = std::move(other.vars); 89 type = other.type; 90 other.type = nullptr; 91 allowWidening = std::move(other.allowWidening); 92 data = std::move(other.data); 93 94 return *this; 95 } 96 66 97 EqvClass::~EqvClass() { 67 98 delete type; 99 } 100 101 void EqvClass::set_type( Type* ty ) { 102 if ( ty == type ) return; 103 delete type; 104 type = ty; 68 105 } 69 106 … … 82 119 } 83 120 84 bool TypeEnvironment::lookup( const std::string &var, EqvClass &eqvClass) const {121 const EqvClass* TypeEnvironment::lookup( const std::string &var ) const { 85 122 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) { 86 if ( i->vars.find( var ) != i->vars.end() ) { 87 /// std::cout << var << " is in class "; 88 /// i->print( std::cout ); 89 eqvClass = *i; 90 return true; 91 } 92 /// std::cout << var << " is not in class "; 93 /// i->print( std::cout ); 94 } // for 95 return false; 96 } 97 98 void TypeEnvironment::add( const EqvClass &eqvClass ) { 99 std::list< EqvClass >::iterator i = env.begin(); 100 while ( i != env.end() ) { 101 std::list< EqvClass >::iterator next = i; 102 next++; 103 std::set< std::string > intersection; 104 std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), std::inserter( intersection, intersection.begin() ) ); 105 if ( ! intersection.empty() ) { 106 env.erase( i ); 107 } // if 123 if ( i->vars.find( var ) != i->vars.end() ) return &*i; 124 } // for 125 return nullptr; 126 } 127 128 /// Removes any class from env that intersects eqvClass 129 void filterOverlappingClasses( std::list<EqvClass> &env, const EqvClass &eqvClass ) { 130 for ( auto i = env.begin(); i != env.end(); ) { 131 auto next = i; 132 ++next; 133 std::set<std::string> intersection; 134 std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 135 std::inserter( intersection, intersection.begin() ) ); 136 if ( ! intersection.empty() ) { env.erase( i ); } 108 137 i = next; 109 } // while 110 env.insert( env.end(), eqvClass ); 138 } 139 } 140 141 void TypeEnvironment::add( EqvClass &&eqvClass ) { 142 filterOverlappingClasses( env, eqvClass ); 143 env.push_back( std::move(eqvClass) ); 111 144 } 112 145 … … 116 149 newClass.vars.insert( (*i)->get_name() ); 117 150 newClass.data = TypeDecl::Data{ (*i) }; 118 env.push_back( newClass ); 119 } // for 151 env.push_back( std::move(newClass) ); 152 } // for 153 } 154 155 void TypeEnvironment::add( const TypeSubstitution & sub ) { 156 EqvClass newClass; 157 for ( auto p : sub ) { 158 newClass.vars.insert( p.first ); 159 newClass.type = p.second->clone(); 160 newClass.allowWidening = false; 161 // Minimal assumptions. Not technically correct, but might be good enough, and 162 // is the best we can do at the moment since information is lost in the 163 // transition to TypeSubstitution 164 newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false }; 165 add( std::move(newClass) ); 166 } 120 167 } 121 168 … … 123 170 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) { 124 171 for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) { 125 /// std::cerr << "adding " << *theVar;126 172 if ( theClass->type ) { 127 /// std::cerr << " bound to ";128 /// theClass->type->print( std::cerr );129 /// std::cerr << std::endl;130 173 sub.add( *theVar, theClass->type ); 131 174 } else if ( theVar != theClass->vars.begin() ) { 132 175 TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype ); 133 /// std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl;134 176 sub.add( *theVar, newTypeInst ); 135 177 delete newTypeInst; … … 137 179 } // for 138 180 } // for 139 /// std::cerr << "input env is:" << std::endl;140 /// print( std::cerr, 8 );141 /// std::cerr << "sub is:" << std::endl;142 /// sub.print( std::cerr, 8 );143 181 sub.normalize(); 144 182 } 145 183 146 184 void TypeEnvironment::print( std::ostream &os, Indenter indent ) const { 147 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i) {148 i->print( os, indent );185 for ( const EqvClass & theClass : env ) { 186 theClass.print( os, indent ); 149 187 } // for 150 188 } … … 152 190 std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) { 153 191 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) { 154 if ( i->vars.find( var ) == i->vars.end() ) { 155 return i; 156 } // if 192 if ( i->vars.count( var ) ) return i; 157 193 } // for 158 194 return env.end(); … … 161 197 void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) { 162 198 env.insert( env.end(), second.env.begin(), second.env.end() ); 163 }164 165 void TypeEnvironment::combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) ) {166 TypeEnvironment secondCopy( second );167 for ( std::list< EqvClass >::iterator firstClass = env.begin(); firstClass != env.end(); ++firstClass ) {168 EqvClass &newClass = *firstClass;169 std::set< std::string > newVars;170 for ( std::set< std::string >::const_iterator var = firstClass->vars.begin(); var != firstClass->vars.end(); ++var ) {171 std::list< EqvClass >::iterator secondClass = secondCopy.internal_lookup( *var );172 if ( secondClass != secondCopy.env.end() ) {173 newVars.insert( secondClass->vars.begin(), secondClass->vars.end() );174 if ( secondClass->type ) {175 if ( newClass.type ) {176 Type *newType = combineFunc( newClass.type, secondClass->type );177 delete newClass.type;178 newClass.type = newType;179 newClass.allowWidening = newClass.allowWidening && secondClass->allowWidening;180 } else {181 newClass.type = secondClass->type->clone();182 newClass.allowWidening = secondClass->allowWidening;183 } // if184 } // if185 secondCopy.env.erase( secondClass );186 } // if187 } // for188 newClass.vars.insert( newVars.begin(), newVars.end() );189 } // for190 for ( std::list< EqvClass >::iterator secondClass = secondCopy.env.begin(); secondClass != secondCopy.env.end(); ++secondClass ) {191 env.push_back( *secondClass );192 } // for193 199 } 194 200 … … 212 218 } 213 219 220 bool isFtype( Type *type ) { 221 if ( dynamic_cast< FunctionType* >( type ) ) { 222 return true; 223 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) { 224 return typeInst->get_isFtype(); 225 } // if 226 return false; 227 } 228 229 bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) { 230 switch ( data.kind ) { 231 case TypeDecl::Dtype: 232 // to bind to an object type variable, the type must not be a function type. 233 // if the type variable is specified to be a complete type then the incoming 234 // type must also be complete 235 // xxx - should this also check that type is not a tuple type and that it's not a ttype? 236 return ! isFtype( type ) && (! data.isComplete || type->isComplete() ); 237 case TypeDecl::Ftype: 238 return isFtype( type ); 239 case TypeDecl::Ttype: 240 // ttype unifies with any tuple type 241 return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type ); 242 default: 243 assertf(false, "Unhandled tyvar kind: %d", data.kind); 244 } // switch 245 return false; 246 } 247 248 bool TypeEnvironment::bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 249 250 // remove references from other, so that type variables can only bind to value types 251 bindTo = bindTo->stripReferences(); 252 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() ); 253 assert( tyvar != openVars.end() ); 254 if ( ! tyVarCompatible( tyvar->second, bindTo ) ) { 255 return false; 256 } // if 257 if ( occurs( bindTo, typeInst->get_name(), *this ) ) { 258 return false; 259 } // if 260 auto curClass = internal_lookup( typeInst->get_name() ); 261 if ( curClass != env.end() ) { 262 if ( curClass->type ) { 263 Type *common = 0; 264 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to 265 std::unique_ptr< Type > newType( curClass->type->clone() ); 266 newType->get_qualifiers() = typeInst->get_qualifiers(); 267 if ( unifyInexact( newType.get(), bindTo, *this, need, have, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) { 268 if ( common ) { 269 common->get_qualifiers() = Type::Qualifiers{}; 270 curClass->set_type( common ); 271 } // if 272 } else return false; 273 } else { 274 Type* newType = bindTo->clone(); 275 newType->get_qualifiers() = Type::Qualifiers{}; 276 curClass->set_type( newType ); 277 curClass->allowWidening = widenMode.widenFirst && widenMode.widenSecond; 278 } // if 279 } else { 280 EqvClass newClass; 281 newClass.vars.insert( typeInst->get_name() ); 282 newClass.type = bindTo->clone(); 283 newClass.type->get_qualifiers() = Type::Qualifiers(); 284 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond; 285 newClass.data = data; 286 env.push_back( std::move(newClass) ); 287 } // if 288 return true; 289 } 290 291 bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 292 293 auto class1 = internal_lookup( var1->get_name() ); 294 auto class2 = internal_lookup( var2->get_name() ); 295 296 // exit early if variables already bound together 297 if ( class1 != env.end() && class1 == class2 ) { 298 class1->allowWidening &= widenMode; 299 return true; 300 } 301 302 bool widen1 = false, widen2 = false; 303 const Type *type1 = nullptr, *type2 = nullptr; 304 305 // check for existing bindings, perform occurs check 306 if ( class1 != env.end() ) { 307 if ( class1->type ) { 308 if ( occurs( class1->type, var2->get_name(), *this ) ) return false; 309 type1 = class1->type; 310 } // if 311 widen1 = widenMode.widenFirst && class1->allowWidening; 312 } // if 313 if ( class2 != env.end() ) { 314 if ( class2->type ) { 315 if ( occurs( class2->type, var1->get_name(), *this ) ) return false; 316 type2 = class2->type; 317 } // if 318 widen2 = widenMode.widenSecond && class2->allowWidening; 319 } // if 320 321 if ( type1 && type2 ) { 322 // both classes bound, merge if bound types can be unified 323 std::unique_ptr<Type> newType1{ type1->clone() }, newType2{ type2->clone() }; 324 WidenMode newWidenMode{ widen1, widen2 }; 325 Type *common = 0; 326 if ( unifyInexact( newType1.get(), newType2.get(), *this, need, have, openVars, newWidenMode, indexer, common ) ) { 327 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 328 class1->allowWidening = widen1 && widen2; 329 if ( common ) { 330 common->get_qualifiers() = Type::Qualifiers{}; 331 class1->set_type( common ); 332 } 333 env.erase( class2 ); 334 } else return false; 335 } else if ( class1 != env.end() && class2 != env.end() ) { 336 // both classes exist, at least one unbound, merge unconditionally 337 if ( type1 ) { 338 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 339 class1->allowWidening = widen1; 340 env.erase( class2 ); 341 } else { 342 class2->vars.insert( class1->vars.begin(), class1->vars.end() ); 343 class2->allowWidening = widen2; 344 env.erase( class1 ); 345 } // if 346 } else if ( class1 != env.end() ) { 347 // var2 unbound, add to class1 348 class1->vars.insert( var2->get_name() ); 349 class1->allowWidening = widen1; 350 } else if ( class2 != env.end() ) { 351 // var1 unbound, add to class2 352 class2->vars.insert( var1->get_name() ); 353 class2->allowWidening = widen2; 354 } else { 355 // neither var bound, create new class 356 EqvClass newClass; 357 newClass.vars.insert( var1->get_name() ); 358 newClass.vars.insert( var2->get_name() ); 359 newClass.allowWidening = widen1 && widen2; 360 newClass.data = data; 361 env.push_back( std::move(newClass) ); 362 } // if 363 return true; 364 } 365 366 void TypeEnvironment::forbidWidening() { 367 for ( EqvClass& c : env ) c.allowWidening = false; 368 } 369 214 370 std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) { 215 371 env.print( out );
Note:
See TracChangeset
for help on using the changeset viewer.