Changeset b067d9b for src/ResolvExpr/TypeEnvironment.cc
- Timestamp:
- Oct 29, 2019, 4:01:24 PM (6 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 773db65, 9421f3d8
- Parents:
- 7951100 (diff), 8364209 (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
r7951100 rb067d9b 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 : Andrew Beach 12 // Last Modified On : Fri Jun 18 14:27:00 2019 13 // Update Count : 5 14 14 // 15 15 … … 17 17 #include <algorithm> // for copy, set_intersection 18 18 #include <iterator> // for ostream_iterator, insert_iterator 19 #include <memory> // for unique_ptr 19 20 #include <utility> // for pair, move 20 21 … … 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 { … … 65 69 } 66 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; 75 } 76 67 77 EqvClass &EqvClass::operator=( const EqvClass &other ) { 68 78 if ( this == &other ) return *this; … … 72 82 } 73 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 74 97 EqvClass::~EqvClass() { 75 98 delete type; 99 } 100 101 void EqvClass::set_type( Type* ty ) { 102 if ( ty == type ) return; 103 delete type; 104 type = ty; 76 105 } 77 106 … … 91 120 92 121 const EqvClass* TypeEnvironment::lookup( const std::string &var ) const { 93 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) { 94 if ( i->vars.find( var ) != i->vars.end() ) { 95 /// std::cout << var << " is in class "; 96 /// i->print( std::cout ); 97 return &*i; 98 } 99 /// std::cout << var << " is not in class "; 100 /// i->print( std::cout ); 122 for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) { 123 if ( i->vars.find( var ) != i->vars.end() ) return &*i; 101 124 } // for 102 125 return nullptr; … … 109 132 ++next; 110 133 std::set<std::string> intersection; 111 std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 134 std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 112 135 std::inserter( intersection, intersection.begin() ) ); 113 136 if ( ! intersection.empty() ) { env.erase( i ); } 114 137 i = next; 115 138 } 116 }117 118 void TypeEnvironment::add( const EqvClass &eqvClass ) {119 filterOverlappingClasses( env, eqvClass );120 env.push_back( eqvClass );121 139 } 122 140 … … 131 149 newClass.vars.insert( (*i)->get_name() ); 132 150 newClass.data = TypeDecl::Data{ (*i) }; 133 env.push_back( newClass);151 env.push_back( std::move(newClass) ); 134 152 } // for 135 153 } … … 145 163 // transition to TypeSubstitution 146 164 newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false }; 147 add( newClass);165 add( std::move(newClass) ); 148 166 } 149 167 } 150 168 151 169 void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const { 152 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {170 for ( ClassList::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) { 153 171 for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) { 154 /// std::cerr << "adding " << *theVar;155 172 if ( theClass->type ) { 156 /// std::cerr << " bound to ";157 /// theClass->type->print( std::cerr );158 /// std::cerr << std::endl;159 173 sub.add( *theVar, theClass->type ); 160 174 } else if ( theVar != theClass->vars.begin() ) { 161 175 TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype ); 162 /// std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl;163 176 sub.add( *theVar, newTypeInst ); 164 177 delete newTypeInst; … … 166 179 } // for 167 180 } // for 168 /// std::cerr << "input env is:" << std::endl;169 /// print( std::cerr, 8 );170 /// std::cerr << "sub is:" << std::endl;171 /// sub.print( std::cerr, 8 );172 181 sub.normalize(); 173 182 } … … 179 188 } 180 189 181 std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) { 182 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) { 183 if ( i->vars.find( var ) == i->vars.end() ) { 184 return i; 185 } // if 190 TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string &var ) { 191 for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) { 192 if ( i->vars.count( var ) ) return i; 186 193 } // for 187 194 return env.end(); … … 192 199 } 193 200 194 void TypeEnvironment::combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) ) { 195 TypeEnvironment secondCopy( second ); 196 for ( std::list< EqvClass >::iterator firstClass = env.begin(); firstClass != env.end(); ++firstClass ) { 197 EqvClass &newClass = *firstClass; 198 std::set< std::string > newVars; 199 for ( std::set< std::string >::const_iterator var = firstClass->vars.begin(); var != firstClass->vars.end(); ++var ) { 200 std::list< EqvClass >::iterator secondClass = secondCopy.internal_lookup( *var ); 201 if ( secondClass != secondCopy.env.end() ) { 202 newVars.insert( secondClass->vars.begin(), secondClass->vars.end() ); 203 if ( secondClass->type ) { 204 if ( newClass.type ) { 205 Type *newType = combineFunc( newClass.type, secondClass->type ); 206 delete newClass.type; 207 newClass.type = newType; 208 newClass.allowWidening = newClass.allowWidening && secondClass->allowWidening; 209 } else { 210 newClass.type = secondClass->type->clone(); 211 newClass.allowWidening = secondClass->allowWidening; 212 } // if 213 } // if 214 secondCopy.env.erase( secondClass ); 215 } // if 216 } // for 217 newClass.vars.insert( newVars.begin(), newVars.end() ); 218 } // for 219 for ( std::list< EqvClass >::iterator secondClass = secondCopy.env.begin(); secondClass != secondCopy.env.end(); ++secondClass ) { 220 env.push_back( *secondClass ); 221 } // for 201 // xxx -- this should maybe be worrying about iterator invalidation (see resolv-proto) 202 bool TypeEnvironment::mergeBound( EqvClass& to, const EqvClass& from, OpenVarSet& openVars, const SymTab::Indexer& indexer ) { 203 if ( from.type ) { 204 if ( to.type ) { 205 // attempt to unify bound types 206 std::unique_ptr<Type> toType{ to.type->clone() }, fromType{ from.type->clone() }; 207 WidenMode widen{ to.allowWidening, from.allowWidening }; 208 Type* common = nullptr; 209 AssertionSet need, have; 210 if ( unifyInexact( toType.get(), fromType.get(), *this, need, have, openVars, widen, indexer, common ) ) { 211 // unifies, set common type if necessary 212 if ( common ) { 213 common->get_qualifiers() = Type::Qualifiers{}; 214 to.set_type( common ); 215 } 216 } else return false; // cannot unify 217 } else { 218 to.type = from.type->clone(); 219 } 220 } 221 222 // unify widening if matches 223 to.allowWidening &= from.allowWidening; 224 return true; 225 } 226 227 // xxx -- this should maybe be worrying about iterator invalidation (see resolv-proto) 228 bool TypeEnvironment::mergeClasses( TypeEnvironment::ClassList::iterator to, TypeEnvironment::ClassList::iterator from, OpenVarSet& openVars, const SymTab::Indexer& indexer ) { 229 EqvClass& r = *to; 230 EqvClass& s = *from; 231 232 // ensure bounds match 233 if ( ! mergeBound( r, s, openVars, indexer ) ) return false; 234 235 // check safely bindable 236 if ( r.type && occursIn( r.type, s.vars.begin(), s.vars.end(), *this ) ) return false; 237 238 // merge classes in 239 r.vars.insert( s.vars.begin(), s.vars.end() ); 240 r.allowWidening &= s.allowWidening; 241 env.erase( from ); 242 243 return true; 244 } 245 246 bool TypeEnvironment::combine( const TypeEnvironment& o, OpenVarSet& openVars, const SymTab::Indexer& indexer ) { 247 // short-circuit easy cases 248 if ( o.isEmpty() ) return true; 249 if ( isEmpty() ) { 250 simpleCombine( o ); 251 return true; 252 } 253 254 // merge classes 255 for ( auto ct = o.env.begin(); ct != o.env.end(); ++ct ) { 256 const EqvClass& c = *ct; 257 258 // typeclass in local environment bound to c 259 auto rt = env.end(); 260 261 // look for first existing bound variable 262 auto vt = c.vars.begin(); 263 for ( ; vt != c.vars.end(); ++vt ) { 264 rt = internal_lookup( *vt ); 265 if ( rt != env.end() ) break; 266 } 267 268 if ( rt != env.end() ) { // c needs to be merged into *rt 269 EqvClass& r = *rt; 270 // merge bindings 271 if ( ! mergeBound( r, c, openVars, indexer ) ) return false; 272 // merge previous unbound variables into this class, checking occurs if needed 273 if ( r.type ) for ( auto ut = c.vars.begin(); ut != vt; ++ut ) { 274 if ( occurs( r.type, *ut, *this ) ) return false; 275 r.vars.insert( *ut ); 276 } else { r.vars.insert( c.vars.begin(), vt ); } 277 // merge subsequent variables into this class (skipping *vt, already there) 278 while ( ++vt != c.vars.end() ) { 279 auto st = internal_lookup( *vt ); 280 if ( st == env.end() ) { 281 // unbound, safe to add if passes occurs 282 if ( r.type && occurs( r.type, *vt, *this ) ) return false; 283 r.vars.insert( *vt ); 284 } else if ( st != rt ) { 285 // bound, but not to the same class 286 if ( ! mergeClasses( rt, st, openVars, indexer ) ) return false; 287 } // ignore bound into the same class 288 } 289 } else { // no variables in c bound; just copy up 290 env.push_back( c ); 291 } 292 } 293 294 // merged all classes 295 return true; 222 296 } 223 297 224 298 void TypeEnvironment::extractOpenVars( OpenVarSet &openVars ) const { 225 for ( std::list< EqvClass >::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) {299 for ( ClassList::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) { 226 300 for ( std::set< std::string >::const_iterator var = eqvClass->vars.begin(); var != eqvClass->vars.end(); ++var ) { 227 301 openVars[ *var ] = eqvClass->data; … … 241 315 } 242 316 317 bool isFtype( const Type * type ) { 318 if ( dynamic_cast< const FunctionType * >( type ) ) { 319 return true; 320 } else if ( const TypeInstType *typeInst = dynamic_cast< const TypeInstType * >( type ) ) { 321 return typeInst->get_isFtype(); 322 } // if 323 return false; 324 } 325 326 bool tyVarCompatible( const TypeDecl::Data & data, const Type * type ) { 327 switch ( data.kind ) { 328 case TypeDecl::Dtype: 329 // to bind to an object type variable, the type must not be a function type. 330 // if the type variable is specified to be a complete type then the incoming 331 // type must also be complete 332 // xxx - should this also check that type is not a tuple type and that it's not a ttype? 333 return ! isFtype( type ) && (! data.isComplete || type->isComplete() ); 334 case TypeDecl::Ftype: 335 return isFtype( type ); 336 case TypeDecl::Ttype: 337 // ttype unifies with any tuple type 338 return dynamic_cast< const TupleType * >( type ) || Tuples::isTtype( type ); 339 default: 340 assertf(false, "Unhandled tyvar kind: %d", data.kind); 341 } // switch 342 return false; 343 } 344 345 bool TypeEnvironment::bindVar( const TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) { 346 347 // remove references from other, so that type variables can only bind to value types 348 bindTo = bindTo->stripReferences(); 349 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() ); 350 assert( tyvar != openVars.end() ); 351 if ( ! tyVarCompatible( tyvar->second, bindTo ) ) { 352 return false; 353 } // if 354 if ( occurs( bindTo, typeInst->get_name(), *this ) ) { 355 return false; 356 } // if 357 auto curClass = internal_lookup( typeInst->get_name() ); 358 if ( curClass != env.end() ) { 359 if ( curClass->type ) { 360 Type *common = 0; 361 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to 362 std::unique_ptr< Type > newType( curClass->type->clone() ); 363 newType->tq = typeInst->tq; 364 if ( unifyInexact( newType.get(), bindTo, *this, need, have, openVars, widen & WidenMode( curClass->allowWidening, true ), indexer, common ) ) { 365 if ( common ) { 366 common->get_qualifiers() = Type::Qualifiers{}; 367 curClass->set_type( common ); 368 } // if 369 } else return false; 370 } else { 371 Type* newType = bindTo->clone(); 372 newType->get_qualifiers() = Type::Qualifiers{}; 373 curClass->set_type( newType ); 374 curClass->allowWidening = widen.first && widen.second; 375 } // if 376 } else { 377 EqvClass newClass; 378 newClass.vars.insert( typeInst->get_name() ); 379 newClass.type = bindTo->clone(); 380 newClass.type->get_qualifiers() = Type::Qualifiers(); 381 newClass.allowWidening = widen.first && widen.second; 382 newClass.data = data; 383 env.push_back( std::move(newClass) ); 384 } // if 385 return true; 386 } 387 388 bool TypeEnvironment::bindVarToVar( const TypeInstType * var1, const TypeInstType * var2, 389 TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, 390 const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) { 391 392 auto class1 = internal_lookup( var1->get_name() ); 393 auto class2 = internal_lookup( var2->get_name() ); 394 395 // exit early if variables already bound together 396 if ( class1 != env.end() && class1 == class2 ) { 397 class1->allowWidening &= widen; 398 return true; 399 } 400 401 bool widen1 = false, widen2 = false; 402 const Type *type1 = nullptr, *type2 = nullptr; 403 404 // check for existing bindings, perform occurs check 405 if ( class1 != env.end() ) { 406 if ( class1->type ) { 407 if ( occurs( class1->type, var2->get_name(), *this ) ) return false; 408 type1 = class1->type; 409 } // if 410 widen1 = widen.first && class1->allowWidening; 411 } // if 412 if ( class2 != env.end() ) { 413 if ( class2->type ) { 414 if ( occurs( class2->type, var1->get_name(), *this ) ) return false; 415 type2 = class2->type; 416 } // if 417 widen2 = widen.second && class2->allowWidening; 418 } // if 419 420 if ( type1 && type2 ) { 421 // both classes bound, merge if bound types can be unified 422 std::unique_ptr<Type> newType1{ type1->clone() }, newType2{ type2->clone() }; 423 WidenMode newWidenMode{ widen1, widen2 }; 424 Type *common = 0; 425 if ( unifyInexact( newType1.get(), newType2.get(), *this, need, have, openVars, newWidenMode, indexer, common ) ) { 426 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 427 class1->allowWidening = widen1 && widen2; 428 if ( common ) { 429 common->get_qualifiers() = Type::Qualifiers{}; 430 class1->set_type( common ); 431 } 432 class1->data.isComplete |= data.isComplete; 433 env.erase( class2 ); 434 } else return false; 435 } else if ( class1 != env.end() && class2 != env.end() ) { 436 // both classes exist, at least one unbound, merge unconditionally 437 if ( type1 ) { 438 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 439 class1->allowWidening = widen1; 440 class1->data.isComplete |= data.isComplete; 441 env.erase( class2 ); 442 } else { 443 class2->vars.insert( class1->vars.begin(), class1->vars.end() ); 444 class2->allowWidening = widen2; 445 class2->data.isComplete |= data.isComplete; 446 env.erase( class1 ); 447 } // if 448 } else if ( class1 != env.end() ) { 449 // var2 unbound, add to class1 450 class1->vars.insert( var2->get_name() ); 451 class1->allowWidening = widen1; 452 class1->data.isComplete |= data.isComplete; 453 } else if ( class2 != env.end() ) { 454 // var1 unbound, add to class2 455 class2->vars.insert( var1->get_name() ); 456 class2->allowWidening = widen2; 457 class2->data.isComplete |= data.isComplete; 458 } else { 459 // neither var bound, create new class 460 EqvClass newClass; 461 newClass.vars.insert( var1->get_name() ); 462 newClass.vars.insert( var2->get_name() ); 463 newClass.allowWidening = widen1 && widen2; 464 newClass.data = data; 465 env.push_back( std::move(newClass) ); 466 } // if 467 return true; 468 } 469 470 void TypeEnvironment::forbidWidening() { 471 for ( EqvClass& c : env ) c.allowWidening = false; 472 } 473 243 474 std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) { 244 475 env.print( out );
Note:
See TracChangeset
for help on using the changeset viewer.