Changeset 6c3a988f
- Timestamp:
- Jan 5, 2017, 3:47:36 PM (8 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- f831177
- Parents:
- 1e3d5b6
- Location:
- src
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
src/GenPoly/Box.cc
r1e3d5b6 r6c3a988f 783 783 void Pass1::boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) { 784 784 for ( std::list< DeclarationWithType *>::const_iterator param = function->get_parameters().begin(); param != function->get_parameters().end(); ++param, ++arg ) { 785 assert ( arg != appExpr->get_args().end() );785 assertf( arg != appExpr->get_args().end(), "boxParams: missing argument for param %s to %s in %s", toString( *param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() ); 786 786 addCast( *arg, (*param)->get_type(), exprTyVars ); 787 787 boxParam( (*param)->get_type(), *arg, exprTyVars ); -
src/GenPoly/Specialize.cc
r1e3d5b6 r6c3a988f 112 112 FunctionType *newType = funType->clone(); 113 113 if ( env ) { 114 TypeSubstitution newEnv( *env );115 114 // it is important to replace only occurrences of type variables that occur free in the 116 115 // thunk's type 117 newEnv.applyFree( newType );116 env->applyFree( newType ); 118 117 } // if 119 118 // create new thunk with same signature as formal type (C linkage, empty body) … … 167 166 assertf( actual->has_result(), "attempting to specialize an untyped expression" ); 168 167 if ( needsSpecialization( formalType, actual->get_result(), env ) ) { 169 FunctionType *funType; 170 if ( ( funType = getFunctionType( formalType ) ) ) { 168 if ( FunctionType *funType = getFunctionType( formalType ) ) { 171 169 ApplicationExpr *appExpr; 172 170 VariableExpr *varExpr; … … 188 186 189 187 bool TupleSpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) { 190 // std::cerr << "asking if type needs tuple spec: " << formalType << std::endl;191 188 if ( FunctionType * ftype = getFunctionType( formalType ) ) { 192 189 return ftype->isTtype(); … … 215 212 void fixLastArg( Expression * last, Iterator begin, Iterator end, OutIterator out ) { 216 213 // safe_dynamic_cast for the assertion 217 safe_dynamic_cast< TupleType * >( last->get_result() ); // xxx - it's quite possible this will trigger for the unary case...214 safe_dynamic_cast< TupleType * >( last->get_result() ); 218 215 unsigned idx = 0; 219 216 for ( ; begin != end; ++begin ) { … … 227 224 Expression * TupleSpecializer::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) { 228 225 static UniqueName thunkNamer( "_tupleThunk" ); 229 // std::cerr << "creating tuple thunk for " << funType << std::endl;230 226 231 227 FunctionType *newType = funType->clone(); 232 228 if ( env ) { 233 TypeSubstitution newEnv( *env );234 229 // it is important to replace only occurrences of type variables that occur free in the 235 230 // thunk's type 236 newEnv.applyFree( newType );231 env->applyFree( newType ); 237 232 } // if 238 233 // create new thunk with same signature as formal type (C linkage, empty body) … … 246 241 UniqueName paramNamer( paramPrefix ); 247 242 ApplicationExpr *appExpr = new ApplicationExpr( actual ); 248 // std::cerr << actual << std::endl; 249 250 FunctionType * actualType = getFunctionType( actual->get_result() ); 243 244 FunctionType * actualType = getFunctionType( actual->get_result() )->clone(); 245 if ( env ) { 246 // need to apply the environment to the actual function's type, since it may itself be polymorphic 247 env->apply( actualType ); 248 } 249 std::unique_ptr< FunctionType > actualTypeManager( actualType ); // for RAII 251 250 std::list< DeclarationWithType * >::iterator actualBegin = actualType->get_parameters().begin(); 252 251 std::list< DeclarationWithType * >::iterator actualEnd = actualType->get_parameters().end(); … … 282 281 std::list< Statement* > oldStmts; 283 282 oldStmts.splice( oldStmts.end(), stmtsToAdd ); 284 spec. handleExplicitParams( appExpr );283 spec.mutate( appExpr ); 285 284 paramPrefix = oldParamPrefix; 286 285 // write any statements added for recursive specializations into the thunk body … … 297 296 } // if 298 297 thunkFunc->get_statements()->get_kids().push_back( appStmt ); 299 300 // std::cerr << "thunkFunc is: " << thunkFunc << std::endl;301 298 302 299 // add thunk definition to queue of statements to add … … 326 323 // don't need to do this for intrinsic calls, because they aren't actually passed 327 324 for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) { 328 inferParam->second.expr = specializer->doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );325 inferParam->second.expr = specializer->doSpecialization( inferParam->second.formalType, inferParam->second.expr, inferParam->second.inferParams.get() ); 329 326 } 330 327 handleExplicitParams( appExpr ); -
src/ResolvExpr/AdjustExprType.cc
r1e3d5b6 r6c3a988f 22 22 class AdjustExprType : public Mutator { 23 23 typedef Mutator Parent; 24 using Parent::mutate; 24 25 public: 25 26 AdjustExprType( const TypeEnvironment &env, const SymTab::Indexer &indexer ); -
src/ResolvExpr/AlternativeFinder.cc
r1e3d5b6 r6c3a988f 339 339 unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar }; 340 340 for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) { 341 needAssertions[ *assert ] = true;341 needAssertions[ *assert ].isUsed = true; 342 342 } 343 343 /// needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() ); … … 380 380 } 381 381 *out++ = arg; 382 return true;383 382 } else if ( actualIt != actualEnd ) { 384 383 // both actualType and formalType are atomic (non-tuple) types - if they unify … … 467 466 void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) { 468 467 for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) { 469 if ( i->second == true) {468 if ( i->second.isUsed ) { 470 469 i->first->accept( indexer ); 471 470 } … … 478 477 if ( begin == end ) { 479 478 if ( newNeed.empty() ) { 479 PRINT( 480 std::cerr << "all assertions satisfied, output alternative: "; 481 newAlt.print( std::cerr ); 482 std::cerr << std::endl; 483 ); 480 484 *out++ = newAlt; 481 485 return; … … 494 498 495 499 ForwardIterator cur = begin++; 496 if ( ! cur->second ) {500 if ( ! cur->second.isUsed ) { 497 501 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out ); 498 502 return; // xxx - should this continue? previously this wasn't here, and it looks like it should be … … 538 542 assert( (*candidate)->get_uniqueId() ); 539 543 DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) ); 544 545 // everything with an empty idChain was pulled in by the current assertion. 546 // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found. 547 for ( auto & a : newerNeed ) { 548 if ( a.second.idChain.empty() ) { 549 a.second.idChain = cur->second.idChain; 550 a.second.idChain.push_back( curDecl->get_uniqueId() ); 551 } 552 } 553 540 554 //AssertionParentSet newNeedParents( needParents ); 541 555 // skip repeatingly-self-recursive assertion satisfaction … … 553 567 ) 554 568 ApplicationExpr *appExpr = static_cast< ApplicationExpr* >( newerAlt.expr ); 569 // follow the current assertion's ID chain to find the correct set of inferred parameters to add the candidate to (i.e. the set of inferred parameters belonging to the entity which requested the assertion parameter). 570 InferredParams * inferParameters = &appExpr->get_inferParams(); 571 for ( UniqueId id : cur->second.idChain ) { 572 inferParameters = (*inferParameters)[ id ].inferParams.get(); 573 } 555 574 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions 556 appExpr->get_inferParams()[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );575 (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr ); 557 576 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out ); 558 577 } else { -
src/ResolvExpr/FindOpenVars.cc
r1e3d5b6 r6c3a988f 50 50 openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) }; 51 51 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) { 52 needAssertions[ *assert ] = false;52 needAssertions[ *assert ].isUsed = false; 53 53 } 54 54 /// cloneAll( (*i)->get_assertions(), needAssertions ); … … 59 59 closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) }; 60 60 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) { 61 haveAssertions[ *assert ] = false;61 haveAssertions[ *assert ].isUsed = false; 62 62 } 63 63 /// cloneAll( (*i)->get_assertions(), haveAssertions ); -
src/ResolvExpr/TypeEnvironment.cc
r1e3d5b6 r6c3a988f 75 75 for ( AssertionSet::const_iterator i = assertions.begin(); i != assertions.end(); ++i ) { 76 76 i->first->print( os, indent ); 77 if ( i->second ) {77 if ( i->second.isUsed ) { 78 78 os << "(used)"; 79 79 } else { -
src/ResolvExpr/TypeEnvironment.h
r1e3d5b6 r6c3a988f 31 31 bool operator()( DeclarationWithType * d1, DeclarationWithType * d2 ) const; 32 32 }; 33 typedef std::map< DeclarationWithType*, bool, AssertCompare > AssertionSet; 33 struct AssertionSetValue { 34 bool isUsed; 35 // chain of Unique IDs of the assertion declarations. The first ID in the chain is the ID of an assertion on the current type, 36 // with each successive ID being the ID of an assertion pulled in by the previous ID. The last ID in the chain is 37 // the ID of the assertion that pulled in the current assertion. 38 std::list< UniqueId > idChain; 39 }; 40 typedef std::map< DeclarationWithType*, AssertionSetValue, AssertCompare > AssertionSet; 34 41 typedef std::map< std::string, TypeDecl::Data > OpenVarSet; 35 42 -
src/ResolvExpr/Unify.cc
r1e3d5b6 r6c3a988f 157 157 // if the type variable is specified to be a complete type then the incoming 158 158 // type must also be complete 159 // xxx - should this also check that type is not a tuple type and that it's not a ttype? 159 160 return ! isFtype( type, indexer ) && (! data.isComplete || isComplete( type )); 160 161 case TypeDecl::Ftype: 161 162 return isFtype( type, indexer ); 162 163 case TypeDecl::Ttype: 163 // ttype eats up any remaining parameters, no matter the type164 return true;164 // ttype unifies with any tuple type 165 return dynamic_cast< TupleType * >( type ); 165 166 } // switch 166 167 return false; … … 433 434 if ( i != assertions.end() ) { 434 435 /// std::cerr << "found it!" << std::endl; 435 i->second = true;436 i->second.isUsed = true; 436 437 } // if 437 438 } … … 488 489 489 490 template< typename Iterator > 490 Type *combineTypes( Iterator begin, Iterator end ) {491 std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end ) { 491 492 std::list< Type * > types; 492 493 for ( ; begin != end; ++begin ) { … … 494 495 flatten( (*begin)->get_type(), back_inserter( types ) ); 495 496 } 496 return new TupleType( Type::Qualifiers(), types);497 return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) ); 497 498 } 498 499 … … 504 505 bool isTtype1 = Tuples::isTtype( t1 ); 505 506 bool isTtype2 = Tuples::isTtype( t2 ); 506 // xxx - assumes ttype must be last parameter; needs cleanup; use unique_ptr for combinedType 507 // xxx - assumes ttype must be last parameter 508 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases. 507 509 if ( isTtype1 && ! isTtype2 ) { 508 510 // combine all of the things in list2, then unify 509 Type * combinedType = combineTypes( list2Begin, list2End ); 510 return unifyExact( t1, combinedType, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 511 return unifyExact( t1, combineTypes( list2Begin, list2End ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 511 512 } else if ( isTtype2 && ! isTtype1 ) { 512 513 // combine all of the things in list1, then unify 513 Type * combinedType = combineTypes( list1Begin, list1End ); 514 return unifyExact( combinedType, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 514 return unifyExact( combineTypes( list1Begin, list1End ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 515 515 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) { 516 516 return false; 517 517 } // if 518 518 } // for 519 // if ( list1Begin != list1End || list2Begin != list2End ) { 520 // return false; 519 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype 521 520 if ( list1Begin != list1End ) { 522 521 // try unifying empty tuple type with ttype 523 522 Type * t1 = (*list1Begin)->get_type(); 524 523 if ( Tuples::isTtype( t1 ) ) { 525 Type * combinedType = combineTypes( list2Begin, list2End ); 526 return unifyExact( t1, combinedType, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 524 return unifyExact( t1, combineTypes( list2Begin, list2End ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 527 525 } else return false; 528 526 } else if ( list2Begin != list2End ) { … … 530 528 Type * t2 = (*list2Begin)->get_type(); 531 529 if ( Tuples::isTtype( t2 ) ) { 532 Type * combinedType = combineTypes( list1Begin, list1End ); 533 return unifyExact( combinedType, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 530 return unifyExact( combineTypes( list1Begin, list1End ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 534 531 } else return false; 535 532 } else { … … 538 535 } 539 536 537 /// Finds ttypes and replaces them with their expansion, if known. 538 /// This needs to be done so that satisfying ttype assertions is easier. 539 /// If this isn't done then argument lists can have wildly different 540 /// size and structure, when they should be compatible. 541 struct TtypeExpander : public Mutator { 542 TypeEnvironment & env; 543 TtypeExpander( TypeEnvironment & env ) : env( env ) {} 544 Type * mutate( TypeInstType * typeInst ) { 545 EqvClass eqvClass; 546 if ( env.lookup( typeInst->get_name(), eqvClass ) ) { 547 if ( eqvClass.data.kind == TypeDecl::Ttype ) { 548 // expand ttype parameter into its actual type 549 if ( eqvClass.type ) { 550 delete typeInst; 551 return eqvClass.type->clone(); 552 } 553 } 554 } 555 return typeInst; 556 } 557 }; 558 559 /// flattens a list of declarations, so that each tuple type has a single declaration. 560 /// makes use of TtypeExpander to ensure ttypes are flat as well. 561 void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) { 562 dst.clear(); 563 for ( DeclarationWithType * dcl : src ) { 564 TtypeExpander expander( env ); 565 dcl->acceptMutator( expander ); 566 std::list< Type * > types; 567 flatten( dcl->get_type(), back_inserter( types ) ); 568 for ( Type * t : types ) { 569 dst.push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, t, nullptr ) ); 570 } 571 delete dcl; 572 } 573 } 574 540 575 void Unify::visit(FunctionType *functionType) { 541 576 FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 ); 542 577 if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) { 578 // flatten the parameter lists for both functions so that tuple structure 579 // doesn't affect unification. Must be a clone so that the types don't change. 580 std::unique_ptr<FunctionType> flatFunc( functionType->clone() ); 581 std::unique_ptr<FunctionType> flatOther( otherFunction->clone() ); 582 flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env ); 583 flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env ); 584 543 585 // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors 544 if ( (functionType->get_parameters().size() == otherFunction->get_parameters().size() && functionType->get_returnVals().size() == otherFunction->get_returnVals().size()) || functionType->isTtype() || otherFunction->isTtype() ) { 545 if ( unifyDeclList( functionType->get_parameters().begin(), functionType->get_parameters().end(), otherFunction->get_parameters().begin(), otherFunction->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 546 if ( unifyDeclList( functionType->get_returnVals().begin(), functionType->get_returnVals().end(), otherFunction->get_returnVals().begin(), otherFunction->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 547 586 if ( (flatFunc->get_parameters().size() == flatOther->get_parameters().size() && flatFunc->get_returnVals().size() == flatOther->get_returnVals().size()) || flatFunc->isTtype() || flatOther->isTtype() ) { 587 if ( unifyDeclList( flatFunc->get_parameters().begin(), flatFunc->get_parameters().end(), flatOther->get_parameters().begin(), flatOther->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 588 if ( unifyDeclList( flatFunc->get_returnVals().begin(), flatFunc->get_returnVals().end(), flatOther->get_returnVals().begin(), flatOther->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 589 590 // the original types must be used in mark assertions, since pointer comparisons are used 548 591 markAssertions( haveAssertions, needAssertions, functionType ); 549 592 markAssertions( haveAssertions, needAssertions, otherFunction ); -
src/ResolvExpr/typeops.h
r1e3d5b6 r6c3a988f 164 164 } 165 165 } else { 166 *out++ = type ;166 *out++ = type->clone(); 167 167 } 168 168 } -
src/SynTree/ApplicationExpr.cc
r1e3d5b6 r6c3a988f 24 24 25 25 ParamEntry::ParamEntry( const ParamEntry &other ) : 26 decl( other.decl ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {26 decl( other.decl ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ), inferParams( new InferredParams( *other.inferParams ) ) { 27 27 } 28 28 … … 34 34 formalType = maybeClone( other.formalType ); 35 35 expr = maybeClone( other.expr ); 36 *inferParams = *other.inferParams; 36 37 return *this; 37 38 } … … 62 63 } 63 64 65 void printInferParams( const InferredParams & inferParams, std::ostream &os, int indent, int level ) { 66 if ( ! inferParams.empty() ) { 67 os << std::string(indent, ' ') << "with inferred parameters " << level << ":" << std::endl; 68 for ( InferredParams::const_iterator i = inferParams.begin(); i != inferParams.end(); ++i ) { 69 os << std::string(indent+2, ' '); 70 Declaration::declFromId( i->second.decl )->printShort( os, indent+2 ); 71 os << std::endl; 72 printInferParams( *i->second.inferParams, os, indent+2, level+1 ); 73 } // for 74 } // if 75 } 76 64 77 void ApplicationExpr::print( std::ostream &os, int indent ) const { 65 78 os << "Application of" << std::endl << std::string(indent+2, ' '); … … 69 82 printAll( args, os, indent+2 ); 70 83 } // if 71 if ( ! inferParams.empty() ) { 72 os << std::string(indent, ' ') << "with inferred parameters:" << std::endl; 73 for ( InferredParams::const_iterator i = inferParams.begin(); i != inferParams.end(); ++i ) { 74 os << std::string(indent+2, ' '); 75 Declaration::declFromId( i->second.decl )->printShort( os, indent+2 ); 76 os << std::endl; 77 } // for 78 } // if 84 printInferParams( inferParams, os, indent+2, 0 ); 79 85 Expression::print( os, indent ); 80 86 } -
src/SynTree/Expression.h
r1e3d5b6 r6c3a988f 54 54 }; 55 55 56 struct ParamEntry; 57 typedef std::map< UniqueId, ParamEntry > InferredParams; 58 56 59 /// ParamEntry contains the i.d. of a declaration and a type that is derived from that declaration, 57 60 /// but subject to decay-to-pointer and type parameter renaming 58 61 struct ParamEntry { 59 ParamEntry(): decl( 0 ), actualType( 0 ), formalType( 0 ), expr( 0 ) {}60 ParamEntry( UniqueId decl, Type *actualType, Type *formalType, Expression* expr ): decl( decl ), actualType( actualType ), formalType( formalType ), expr( expr ) {}62 ParamEntry(): decl( 0 ), actualType( 0 ), formalType( 0 ), expr( 0 ), inferParams( new InferredParams ) {} 63 ParamEntry( UniqueId decl, Type *actualType, Type *formalType, Expression* expr ): decl( decl ), actualType( actualType ), formalType( formalType ), expr( expr ), inferParams( new InferredParams ) {} 61 64 ParamEntry( const ParamEntry &other ); 62 65 ~ParamEntry(); … … 67 70 Type *formalType; 68 71 Expression* expr; 69 }; 70 71 typedef std::map< UniqueId, ParamEntry > InferredParams; 72 std::unique_ptr< InferredParams > inferParams; 73 }; 72 74 73 75 /// ApplicationExpr represents the application of a function to a set of parameters. This is the result of running an -
src/SynTree/TupleExpr.cc
r1e3d5b6 r6c3a988f 58 58 TupleIndexExpr::TupleIndexExpr( Expression * tuple, unsigned int index ) : tuple( tuple ), index( index ) { 59 59 TupleType * type = safe_dynamic_cast< TupleType * >( tuple->get_result() ); 60 assertf( type->size() > index, "TupleIndexExpr index out of bounds: tuple size %d, requested index %d ", type->size(), index);60 assertf( type->size() > index, "TupleIndexExpr index out of bounds: tuple size %d, requested index %d in expr %s", type->size(), index, toString( tuple ).c_str() ); 61 61 set_result( (*std::next( type->get_types().begin(), index ))->clone() ); 62 62 get_result()->set_isLvalue( type->get_isLvalue() );
Note: See TracChangeset
for help on using the changeset viewer.