source: src/ResolvExpr/AlternativeFinder.cc@ 7e4c4f4

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 7e4c4f4 was 7e4c4f4, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Update debug prints in AlternativeFinder

  • Property mode set to 100644
File size: 65.9 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// AlternativeFinder.cc --
8//
9// Author : Richard C. Bilson
10// Created On : Sat May 16 23:52:08 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Mon Aug 28 13:47:24 2017
13// Update Count : 32
14//
15
16#include <algorithm> // for copy
17#include <cassert> // for strict_dynamic_cast, assert, assertf
18#include <iostream> // for operator<<, cerr, ostream, endl
19#include <iterator> // for back_insert_iterator, back_inserter
20#include <list> // for _List_iterator, list, _List_const_...
21#include <map> // for _Rb_tree_iterator, map, _Rb_tree_c...
22#include <memory> // for allocator_traits<>::value_type
23#include <utility> // for pair
24#include <vector> // for vector
25
26#include "Alternative.h" // for AltList, Alternative
27#include "AlternativeFinder.h"
28#include "Common/SemanticError.h" // for SemanticError
29#include "Common/utility.h" // for deleteAll, printAll, CodeLocation
30#include "Cost.h" // for Cost, Cost::zero, operator<<, Cost...
31#include "InitTweak/InitTweak.h" // for getFunctionName
32#include "RenameVars.h" // for RenameVars, global_renamer
33#include "ResolveTypeof.h" // for resolveTypeof
34#include "Resolver.h" // for resolveStmtExpr
35#include "SymTab/Indexer.h" // for Indexer
36#include "SymTab/Mangler.h" // for Mangler
37#include "SymTab/Validate.h" // for validateType
38#include "SynTree/Constant.h" // for Constant
39#include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec...
40#include "SynTree/Expression.h" // for Expression, CastExpr, NameExpr
41#include "SynTree/Initializer.h" // for SingleInit, operator<<, Designation
42#include "SynTree/SynTree.h" // for UniqueId
43#include "SynTree/Type.h" // for Type, FunctionType, PointerType
44#include "Tuples/Explode.h" // for explode
45#include "Tuples/Tuples.h" // for isTtype, handleTupleAssignment
46#include "Unify.h" // for unify
47#include "typeops.h" // for adjustExprType, polyCost, castCost
48
49extern bool resolvep;
50#define PRINT( text ) if ( resolvep ) { text }
51//#define DEBUG_COST
52
53namespace ResolvExpr {
54 Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
55 CastExpr *castToVoid = new CastExpr( expr );
56
57 AlternativeFinder finder( indexer, env );
58 finder.findWithAdjustment( castToVoid );
59
60 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
61 // interpretations, an exception has already been thrown.
62 assert( finder.get_alternatives().size() == 1 );
63 CastExpr *newExpr = dynamic_cast< CastExpr* >( finder.get_alternatives().front().expr );
64 assert( newExpr );
65 env = finder.get_alternatives().front().env;
66 return newExpr->get_arg()->clone();
67 }
68
69 Cost sumCost( const AltList &in ) {
70 Cost total = Cost::zero;
71 for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
72 total += i->cost;
73 }
74 return total;
75 }
76
77 namespace {
78 void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt = 0 ) {
79 Indenter indent = { Indenter::tabsize, indentAmt };
80 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
81 i->print( os, indent );
82 os << std::endl;
83 }
84 }
85
86 void makeExprList( const AltList &in, std::list< Expression* > &out ) {
87 for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
88 out.push_back( i->expr->clone() );
89 }
90 }
91
92 struct PruneStruct {
93 bool isAmbiguous;
94 AltList::iterator candidate;
95 PruneStruct() {}
96 PruneStruct( AltList::iterator candidate ): isAmbiguous( false ), candidate( candidate ) {}
97 };
98
99 /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations
100 template< typename InputIterator, typename OutputIterator >
101 void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) {
102 // select the alternatives that have the minimum conversion cost for a particular set of result types
103 std::map< std::string, PruneStruct > selected;
104 for ( AltList::iterator candidate = begin; candidate != end; ++candidate ) {
105 PruneStruct current( candidate );
106 std::string mangleName;
107 {
108 Type * newType = candidate->expr->get_result()->clone();
109 candidate->env.apply( newType );
110 mangleName = SymTab::Mangler::mangle( newType );
111 delete newType;
112 }
113 std::map< std::string, PruneStruct >::iterator mapPlace = selected.find( mangleName );
114 if ( mapPlace != selected.end() ) {
115 if ( candidate->cost < mapPlace->second.candidate->cost ) {
116 PRINT(
117 std::cerr << "cost " << candidate->cost << " beats " << mapPlace->second.candidate->cost << std::endl;
118 )
119 selected[ mangleName ] = current;
120 } else if ( candidate->cost == mapPlace->second.candidate->cost ) {
121 PRINT(
122 std::cerr << "marking ambiguous" << std::endl;
123 )
124 mapPlace->second.isAmbiguous = true;
125 } else {
126 PRINT(
127 std::cerr << "cost " << candidate->cost << " loses to " << mapPlace->second.candidate->cost << std::endl;
128 )
129 }
130 } else {
131 selected[ mangleName ] = current;
132 }
133 }
134
135 // accept the alternatives that were unambiguous
136 for ( std::map< std::string, PruneStruct >::iterator target = selected.begin(); target != selected.end(); ++target ) {
137 if ( ! target->second.isAmbiguous ) {
138 Alternative &alt = *target->second.candidate;
139 alt.env.applyFree( alt.expr->get_result() );
140 *out++ = alt;
141 }
142 }
143 }
144
145 void renameTypes( Expression *expr ) {
146 expr->get_result()->accept( global_renamer );
147 }
148 } // namespace
149
150 void referenceToRvalueConversion( Expression *& expr ) {
151 if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
152 // cast away reference from expr
153 expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
154 }
155 }
156
157 template< typename InputIterator, typename OutputIterator >
158 void AlternativeFinder::findSubExprs( InputIterator begin, InputIterator end, OutputIterator out ) {
159 while ( begin != end ) {
160 AlternativeFinder finder( indexer, env );
161 finder.findWithAdjustment( *begin );
162 // XXX either this
163 //Designators::fixDesignations( finder, (*begin++)->get_argName() );
164 // or XXX this
165 begin++;
166 PRINT(
167 std::cerr << "findSubExprs" << std::endl;
168 printAlts( finder.alternatives, std::cerr );
169 )
170 *out++ = finder;
171 }
172 }
173
174 AlternativeFinder::AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env )
175 : indexer( indexer ), env( env ) {
176 }
177
178 void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
179 expr->accept( *this );
180 if ( failFast && alternatives.empty() ) {
181 throw SemanticError( "No reasonable alternatives for expression ", expr );
182 }
183 if ( prune ) {
184 auto oldsize = alternatives.size();
185 PRINT(
186 std::cerr << "alternatives before prune:" << std::endl;
187 printAlts( alternatives, std::cerr );
188 )
189 AltList::iterator oldBegin = alternatives.begin();
190 pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) );
191 if ( failFast && alternatives.begin() == oldBegin ) {
192 std::ostringstream stream;
193 AltList winners;
194 findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
195 stream << "Cannot choose between " << winners.size() << " alternatives for expression\n";
196 expr->print( stream );
197 stream << "Alternatives are:\n";
198 printAlts( winners, stream, 1 );
199 throw SemanticError( stream.str() );
200 }
201 alternatives.erase( oldBegin, alternatives.end() );
202 PRINT(
203 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
204 )
205 PRINT(
206 std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl;
207 )
208 }
209 // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
210 for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
211 if ( adjust ) {
212 adjustExprType( i->expr->get_result(), i->env, indexer );
213 }
214 }
215
216 // Central location to handle gcc extension keyword, etc. for all expression types.
217 for ( Alternative &iter: alternatives ) {
218 iter.expr->set_extension( expr->get_extension() );
219 iter.expr->location = expr->location;
220 } // for
221 }
222
223 void AlternativeFinder::findWithAdjustment( Expression *expr ) {
224 find( expr, true );
225 }
226
227 void AlternativeFinder::findWithoutPrune( Expression * expr ) {
228 find( expr, true, false );
229 }
230
231 void AlternativeFinder::maybeFind( Expression * expr ) {
232 find( expr, true, true, false );
233 }
234
235 void AlternativeFinder::addAnonConversions( const Alternative & alt ) {
236 // adds anonymous member interpretations whenever an aggregate value type is seen.
237 // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
238 std::unique_ptr<Expression> aggrExpr( alt.expr->clone() );
239 alt.env.apply( aggrExpr->get_result() );
240 Type * aggrType = aggrExpr->get_result();
241 if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
242 aggrType = aggrType->stripReferences();
243 aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
244 }
245
246 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
247 NameExpr nameExpr( "" );
248 addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr );
249 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
250 NameExpr nameExpr( "" );
251 addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr );
252 } // if
253 }
254
255 template< typename StructOrUnionType >
256 void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
257 // by this point, member must be a name expr
258 NameExpr * nameExpr = dynamic_cast< NameExpr * >( member );
259 if ( ! nameExpr ) return;
260 const std::string & name = nameExpr->get_name();
261 std::list< Declaration* > members;
262 aggInst->lookup( name, members );
263
264 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
265 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
266 alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) );
267 renameTypes( alternatives.back().expr );
268 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
269 } else {
270 assert( false );
271 }
272 }
273 }
274
275 void AlternativeFinder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
276 if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
277 // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
278 // xxx - this should be improved by memoizing the value of constant exprs
279 // during parsing and reusing that information here.
280 std::stringstream ss( constantExpr->get_constant()->get_value() );
281 int val = 0;
282 std::string tmp;
283 if ( ss >> val && ! (ss >> tmp) ) {
284 if ( val >= 0 && (unsigned int)val < tupleType->size() ) {
285 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
286 } // if
287 } // if
288 } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {
289 // xxx - temporary hack until 0/1 are int constants
290 if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {
291 std::stringstream ss( nameExpr->get_name() );
292 int val;
293 ss >> val;
294 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
295 }
296 } // if
297 }
298
299 void AlternativeFinder::visit( ApplicationExpr *applicationExpr ) {
300 alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
301 }
302
303 Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
304 PRINT(
305 std::cerr << std::endl << "converting ";
306 actualType->print( std::cerr, 8 );
307 std::cerr << std::endl << " to ";
308 formalType->print( std::cerr, 8 );
309 std::cerr << std::endl << "environment is: ";
310 env.print( std::cerr, 8 );
311 std::cerr << std::endl;
312 )
313 Cost convCost = conversionCost( actualType, formalType, indexer, env );
314 PRINT(
315 std::cerr << std::endl << "cost is " << convCost << std::endl;
316 )
317 if ( convCost == Cost::infinity ) {
318 return convCost;
319 }
320 convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) );
321 PRINT(
322 std::cerr << "cost with polycost is " << convCost << std::endl;
323 )
324 return convCost;
325 }
326
327 Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
328 Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
329
330 // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion.
331 // ignore poly cost for now, since this requires resolution of the cast to infer parameters and this
332 // does not currently work for the reason stated below.
333 Cost tmpCost = convCost;
334 tmpCost.incPoly( -tmpCost.get_polyCost() );
335 if ( tmpCost != Cost::zero ) {
336 Type *newType = formalType->clone();
337 env.apply( newType );
338 actualExpr = new CastExpr( actualExpr, newType );
339 // xxx - SHOULD be able to resolve this cast, but at the moment pointers are not castable to zero_t, but are implicitly convertible. This is clearly
340 // inconsistent, once this is fixed it should be possible to resolve the cast.
341 // xxx - this isn't working, it appears because type1 (the formal type) is seen as widenable, but it shouldn't be, because this makes the conversion from DT* to DT* since commontype(zero_t, DT*) is DT*, rather than just nothing.
342
343 // AlternativeFinder finder( indexer, env );
344 // finder.findWithAdjustment( actualExpr );
345 // assertf( finder.get_alternatives().size() > 0, "Somehow castable expression failed to find alternatives." );
346 // assertf( finder.get_alternatives().size() == 1, "Somehow got multiple alternatives for known cast expression." );
347 // Alternative & alt = finder.get_alternatives().front();
348 // delete actualExpr;
349 // actualExpr = alt.expr->clone();
350 }
351 return convCost;
352 }
353
354 Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
355 ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr );
356 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
357 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
358
359 Cost convCost = Cost::zero;
360 std::list< DeclarationWithType* >& formals = function->get_parameters();
361 std::list< DeclarationWithType* >::iterator formal = formals.begin();
362 std::list< Expression* >& actuals = appExpr->get_args();
363
364 for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
365 Type * actualType = (*actualExpr)->get_result();
366 PRINT(
367 std::cerr << "actual expression:" << std::endl;
368 (*actualExpr)->print( std::cerr, 8 );
369 std::cerr << "--- results are" << std::endl;
370 actualType->print( std::cerr, 8 );
371 )
372 if ( formal == formals.end() ) {
373 if ( function->get_isVarArgs() ) {
374 convCost.incUnsafe();
375 PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
376 // convert reference-typed expressions to value-typed expressions
377 referenceToRvalueConversion( *actualExpr );
378 continue;
379 } else {
380 return Cost::infinity;
381 }
382 }
383 Type * formalType = (*formal)->get_type();
384 convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
385 ++formal; // can't be in for-loop update because of the continue
386 }
387 if ( formal != formals.end() ) {
388 return Cost::infinity;
389 }
390
391 for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
392 convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
393 }
394
395 return convCost;
396 }
397
398 /// Adds type variables to the open variable set and marks their assertions
399 void makeUnifiableVars( Type *type, OpenVarSet &unifiableVars, AssertionSet &needAssertions ) {
400 for ( Type::ForallList::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
401 unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar };
402 for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
403 needAssertions[ *assert ].isUsed = true;
404 }
405/// needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
406 }
407 }
408
409 // /// Map of declaration uniqueIds (intended to be the assertions in an AssertionSet) to their parents and the number of times they've been included
410 //typedef std::unordered_map< UniqueId, std::unordered_map< UniqueId, unsigned > > AssertionParentSet;
411
412 static const int recursionLimit = /*10*/ 4; ///< Limit to depth of recursion satisfaction
413 //static const unsigned recursionParentLimit = 1; ///< Limit to the number of times an assertion can recursively use itself
414
415 void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
416 for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
417 if ( i->second.isUsed ) {
418 indexer.addId( i->first );
419 }
420 }
421 }
422
423 template< typename ForwardIterator, typename OutputIterator >
424 void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/
425 int level, const SymTab::Indexer &indexer, OutputIterator out ) {
426 if ( begin == end ) {
427 if ( newNeed.empty() ) {
428 PRINT(
429 std::cerr << "all assertions satisfied, output alternative: ";
430 newAlt.print( std::cerr );
431 std::cerr << std::endl;
432 );
433 *out++ = newAlt;
434 return;
435 } else if ( level >= recursionLimit ) {
436 throw SemanticError( "Too many recursive assertions" );
437 } else {
438 AssertionSet newerNeed;
439 PRINT(
440 std::cerr << "recursing with new set:" << std::endl;
441 printAssertionSet( newNeed, std::cerr, 8 );
442 )
443 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, /*needParents,*/ level+1, indexer, out );
444 return;
445 }
446 }
447
448 ForwardIterator cur = begin++;
449 if ( ! cur->second.isUsed ) {
450 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out );
451 return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
452 }
453 DeclarationWithType *curDecl = cur->first;
454
455 PRINT(
456 std::cerr << "inferRecursive: assertion is ";
457 curDecl->print( std::cerr );
458 std::cerr << std::endl;
459 )
460 std::list< DeclarationWithType* > candidates;
461 decls.lookupId( curDecl->get_name(), candidates );
462/// if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
463 for ( std::list< DeclarationWithType* >::const_iterator candidate = candidates.begin(); candidate != candidates.end(); ++candidate ) {
464 PRINT(
465 std::cerr << "inferRecursive: candidate is ";
466 (*candidate)->print( std::cerr );
467 std::cerr << std::endl;
468 )
469
470 AssertionSet newHave, newerNeed( newNeed );
471 TypeEnvironment newEnv( newAlt.env );
472 OpenVarSet newOpenVars( openVars );
473 Type *adjType = (*candidate)->get_type()->clone();
474 adjustExprType( adjType, newEnv, indexer );
475 adjType->accept( global_renamer );
476 PRINT(
477 std::cerr << "unifying ";
478 curDecl->get_type()->print( std::cerr );
479 std::cerr << " with ";
480 adjType->print( std::cerr );
481 std::cerr << std::endl;
482 )
483 if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
484 PRINT(
485 std::cerr << "success!" << std::endl;
486 )
487 SymTab::Indexer newDecls( decls );
488 addToIndexer( newHave, newDecls );
489 Alternative newerAlt( newAlt );
490 newerAlt.env = newEnv;
491 assertf( (*candidate)->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( *candidate ).c_str() );
492 DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) );
493
494 // everything with an empty idChain was pulled in by the current assertion.
495 // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
496 for ( auto & a : newerNeed ) {
497 if ( a.second.idChain.empty() ) {
498 a.second.idChain = cur->second.idChain;
499 a.second.idChain.push_back( curDecl->get_uniqueId() );
500 }
501 }
502
503 //AssertionParentSet newNeedParents( needParents );
504 // skip repeatingly-self-recursive assertion satisfaction
505 // DOESN'T WORK: grandchild nodes conflict with their cousins
506 //if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue;
507 Expression *varExpr = new VariableExpr( candDecl );
508 delete varExpr->get_result();
509 varExpr->set_result( adjType->clone() );
510 PRINT(
511 std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
512 curDecl->print( std::cerr );
513 std::cerr << " with declaration " << (*candidate)->get_uniqueId() << " ";
514 (*candidate)->print( std::cerr );
515 std::cerr << std::endl;
516 )
517 // 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).
518 InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
519 for ( UniqueId id : cur->second.idChain ) {
520 inferParameters = (*inferParameters)[ id ].inferParams.get();
521 }
522 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
523 (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
524 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out );
525 } else {
526 delete adjType;
527 }
528 }
529 }
530
531 template< typename OutputIterator >
532 void AlternativeFinder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
533// PRINT(
534// std::cerr << "inferParameters: assertions needed are" << std::endl;
535// printAll( need, std::cerr, 8 );
536// )
537 SymTab::Indexer decls( indexer );
538 // PRINT(
539 // std::cerr << "============= original indexer" << std::endl;
540 // indexer.print( std::cerr );
541 // std::cerr << "============= new indexer" << std::endl;
542 // decls.print( std::cerr );
543 // )
544 addToIndexer( have, decls );
545 AssertionSet newNeed;
546 //AssertionParentSet needParents;
547 PRINT(
548 std::cerr << "env is: " << std::endl;
549 newAlt.env.print( std::cerr, 0 );
550 std::cerr << std::endl;
551 )
552
553 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, /*needParents,*/ 0, indexer, out );
554// PRINT(
555// std::cerr << "declaration 14 is ";
556// Declaration::declFromId
557// *out++ = newAlt;
558// )
559 }
560
561 /// Gets a default value from an initializer, nullptr if not present
562 ConstantExpr* getDefaultValue( Initializer* init ) {
563 if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
564 if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->get_value() ) ) {
565 return dynamic_cast<ConstantExpr*>( ce->get_arg() );
566 }
567 }
568 return nullptr;
569 }
570
571 /// State to iteratively build a match of parameter expressions to arguments
572 struct ArgPack {
573 AltList actuals; ///< Arguments included in this pack
574 TypeEnvironment env; ///< Environment for this pack
575 AssertionSet need; ///< Assertions outstanding for this pack
576 AssertionSet have; ///< Assertions found for this pack
577 OpenVarSet openVars; ///< Open variables for this pack
578 unsigned nextArg; ///< Index of next argument in arguments list
579 std::vector<Alternative> expls; ///< Exploded actuals left over from last match
580 unsigned nextExpl; ///< Index of next exploded alternative to use
581 std::vector<unsigned> tupleEls; /// Number of elements in current tuple element(s)
582
583 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
584 const OpenVarSet& openVars)
585 : actuals(), env(env), need(need), have(have), openVars(openVars), nextArg(0),
586 expls(), nextExpl(0), tupleEls() {}
587
588 /// Starts a new tuple expression
589 void beginTuple() {
590 if ( ! tupleEls.empty() ) ++tupleEls.back();
591 tupleEls.push_back(0);
592 }
593
594 /// Ends a tuple expression, consolidating the appropriate actuals
595 void endTuple() {
596 // set up new Tuple alternative
597 std::list<Expression*> exprs;
598 Cost cost = Cost::zero;
599
600 // transfer elements into alternative
601 for (unsigned i = 0; i < tupleEls.back(); ++i) {
602 exprs.push_front( actuals.back().expr );
603 actuals.back().expr = nullptr;
604 cost += actuals.back().cost;
605 actuals.pop_back();
606 }
607 tupleEls.pop_back();
608
609 // build new alternative
610 actuals.emplace_back( new TupleExpr( exprs ), this->env, cost );
611 }
612
613 /// Clones and adds an actual, returns this
614 ArgPack& withArg( Expression* expr, Cost cost = Cost::zero ) {
615 actuals.emplace_back( expr->clone(), this->env, cost );
616 if ( ! tupleEls.empty() ) ++tupleEls.back();
617 return *this;
618 }
619 };
620
621 /// Instantiates an argument to match a formal, returns false if no results left
622 bool instantiateArgument( Type* formalType, Initializer* initializer,
623 const std::vector< AlternativeFinder >& args,
624 std::vector<ArgPack>& results, std::vector<ArgPack>& nextResults,
625 const SymTab::Indexer& indexer ) {
626 if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
627 // formalType is a TupleType - group actuals into a TupleExpr
628 for ( ArgPack& result : results ) { result.beginTuple(); }
629 for ( Type* type : *tupleType ) {
630 // xxx - dropping initializer changes behaviour from previous, but seems correct
631 if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) )
632 return false;
633 }
634 for ( ArgPack& result : results ) { result.endTuple(); }
635 return true;
636 } else if ( TypeInstType* ttype = Tuples::isTtype( formalType ) ) {
637 // formalType is a ttype, consumes all remaining arguments
638 // xxx - mixing default arguments with variadic??
639 std::vector<ArgPack> finalResults{}; /// list of completed tuples
640 // start tuples
641 for ( ArgPack& result : results ) {
642 result.beginTuple();
643
644 // use rest of exploded tuple if present
645 while ( result.nextExpl < result.expls.size() ) {
646 const Alternative& actual = result.expls[result.nextExpl];
647 result.env.addActual( actual.env, result.openVars );
648 result.withArg( actual.expr );
649 ++result.nextExpl;
650 }
651 }
652 // iterate until all results completed
653 while ( ! results.empty() ) {
654 // add another argument to results
655 for ( ArgPack& result : results ) {
656 // finish result when out of arguments
657 if ( result.nextArg >= args.size() ) {
658 Type* argType = result.actuals.back().expr->get_result();
659 if ( result.tupleEls.back() == 1 && Tuples::isTtype( argType ) ) {
660 // the case where a ttype value is passed directly is special, e.g. for
661 // argument forwarding purposes
662 // xxx - what if passing multiple arguments, last of which is ttype?
663 // xxx - what would happen if unify was changed so that unifying tuple
664 // types flattened both before unifying lists? then pass in TupleType
665 // (ttype) below.
666 result.tupleEls.pop_back();
667 } else {
668 // collapse leftover arguments into tuple
669 result.endTuple();
670 argType = result.actuals.back().expr->get_result();
671 }
672 // check unification for ttype before adding to final
673 if ( unify( ttype, argType, result.env, result.need, result.have,
674 result.openVars, indexer ) ) {
675 finalResults.push_back( std::move(result) );
676 }
677 continue;
678 }
679
680 // add each possible next argument
681 for ( const Alternative& actual : args[result.nextArg] ) {
682 ArgPack aResult = result; // copy to clone everything
683 // add details of actual to result
684 aResult.env.addActual( actual.env, aResult.openVars );
685 Cost cost = actual.cost;
686
687 // explode argument
688 std::vector<Alternative> exploded;
689 Tuples::explode( actual, indexer, back_inserter( exploded ) );
690
691 // add exploded argument to tuple
692 for ( Alternative& aActual : exploded ) {
693 aResult.withArg( aActual.expr, cost );
694 cost = Cost::zero;
695 }
696 ++aResult.nextArg;
697 nextResults.push_back( std::move(aResult) );
698 }
699 }
700
701 // reset for next round
702 results.swap( nextResults );
703 nextResults.clear();
704 }
705 results.swap( finalResults );
706 return ! results.empty();
707 }
708
709 // iterate each current subresult
710 for ( unsigned iResult = 0; iResult < results.size(); ++iResult ) {
711 ArgPack& result = results[iResult];
712
713 if ( result.nextExpl < result.expls.size() ) {
714 // use remainder of exploded tuple if present
715 const Alternative& actual = result.expls[result.nextExpl];
716 result.env.addActual( actual.env, result.openVars );
717 Type* actualType = actual.expr->get_result();
718
719 PRINT(
720 std::cerr << "formal type is ";
721 formalType->print( std::cerr );
722 std::cerr << std::endl << "actual type is ";
723 actualType->print( std::cerr );
724 std::cerr << std::endl;
725 )
726
727 if ( unify( formalType, actualType, result.env, result.need, result.have,
728 result.openVars, indexer ) ) {
729 ++result.nextExpl;
730 nextResults.push_back( std::move(result.withArg( actual.expr )) );
731 }
732
733 continue;
734 } else if ( result.nextArg >= args.size() ) {
735 // use default initializers if out of arguments
736 if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
737 if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
738 if ( unify( formalType, cnst->get_type(), result.env, result.need,
739 result.have, result.openVars, indexer ) ) {
740 nextResults.push_back( std::move(result.withArg( cnstExpr )) );
741 }
742 }
743 }
744 continue;
745 }
746
747 // Check each possible next argument
748 for ( const Alternative& actual : args[result.nextArg] ) {
749 ArgPack aResult = result; // copy to clone everything
750 // add details of actual to result
751 aResult.env.addActual( actual.env, aResult.openVars );
752
753 // explode argument
754 std::vector<Alternative> exploded;
755 Tuples::explode( actual, indexer, back_inserter( exploded ) );
756 if ( exploded.empty() ) {
757 // skip empty tuple arguments
758 ++aResult.nextArg;
759 results.push_back( std::move(aResult) );
760 continue;
761 }
762
763 // consider only first exploded actual
764 const Alternative& aActual = exploded.front();
765 Type* actualType = aActual.expr->get_result()->clone();
766
767 PRINT(
768 std::cerr << "formal type is ";
769 formalType->print( std::cerr );
770 std::cerr << std::endl << "actual type is ";
771 actualType->print( std::cerr );
772 std::cerr << std::endl;
773 )
774
775 // attempt to unify types
776 if ( unify( formalType, actualType, aResult.env, aResult.need, aResult.have, aResult.openVars, indexer ) ) {
777 // add argument
778 aResult.withArg( aActual.expr, actual.cost );
779 ++aResult.nextArg;
780 if ( exploded.size() > 1 ) {
781 // other parts of tuple left over
782 aResult.expls = std::move( exploded );
783 aResult.nextExpl = 1;
784 }
785 nextResults.push_back( std::move(aResult) );
786 }
787 }
788 }
789
790 // reset for next parameter
791 results.swap( nextResults );
792 nextResults.clear();
793
794 return ! results.empty();
795 }
796
797 template<typename OutputIterator>
798 void AlternativeFinder::makeFunctionAlternatives( const Alternative &func,
799 FunctionType *funcType, const std::vector< AlternativeFinder > &args,
800 OutputIterator out ) {
801 OpenVarSet funcOpenVars;
802 AssertionSet funcNeed, funcHave;
803 TypeEnvironment funcEnv( func.env );
804 makeUnifiableVars( funcType, funcOpenVars, funcNeed );
805 // add all type variables as open variables now so that those not used in the parameter
806 // list are still considered open.
807 funcEnv.add( funcType->get_forall() );
808
809 if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
810 // attempt to narrow based on expected target type
811 Type * returnType = funcType->get_returnVals().front()->get_type();
812 if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
813 indexer ) ) {
814 // unification failed, don't pursue this function alternative
815 return;
816 }
817 }
818
819 // iteratively build matches, one parameter at a time
820 std::vector<ArgPack> results{ ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } };
821 std::vector<ArgPack> nextResults{};
822 for ( DeclarationWithType* formal : funcType->get_parameters() ) {
823 ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
824 if ( ! instantiateArgument(
825 obj->get_type(), obj->get_init(), args, results, nextResults, indexer ) )
826 return;
827 }
828
829 // filter out results that don't use all the arguments, and aren't variadic
830 std::vector<ArgPack> finalResults{};
831 if ( funcType->get_isVarArgs() ) {
832 for ( ArgPack& result : results ) {
833 // use rest of exploded tuple if present
834 while ( result.nextExpl < result.expls.size() ) {
835 const Alternative& actual = result.expls[result.nextExpl];
836 result.env.addActual( actual.env, result.openVars );
837 result.withArg( actual.expr );
838 ++result.nextExpl;
839 }
840 }
841
842 while ( ! results.empty() ) {
843 // build combinations for all remaining arguments
844 for ( ArgPack& result : results ) {
845 // keep if used all arguments
846 if ( result.nextArg >= args.size() ) {
847 finalResults.push_back( std::move(result) );
848 continue;
849 }
850
851 // add each possible next argument
852 for ( const Alternative& actual : args[result.nextArg] ) {
853 ArgPack aResult = result; // copy to clone everything
854 // add details of actual to result
855 aResult.env.addActual( actual.env, aResult.openVars );
856 Cost cost = actual.cost;
857
858 // explode argument
859 std::vector<Alternative> exploded;
860 Tuples::explode( actual, indexer, back_inserter( exploded ) );
861
862 // add exploded argument to arg list
863 for ( Alternative& aActual : exploded ) {
864 aResult.withArg( aActual.expr, cost );
865 cost = Cost::zero;
866 }
867 ++aResult.nextArg;
868 nextResults.push_back( std::move(aResult) );
869 }
870 }
871
872 // reset for next round
873 results.swap( nextResults );
874 nextResults.clear();
875 }
876 } else {
877 // filter out results that don't use all the arguments
878 for ( ArgPack& result : results ) {
879 if ( result.nextExpl >= result.expls.size() && result.nextArg >= args.size() ) {
880 finalResults.push_back( std::move(result) );
881 }
882 }
883 }
884
885 // validate matching combos, add to final result list
886 for ( ArgPack& result : finalResults ) {
887 ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
888 Alternative newAlt( appExpr, result.env, sumCost( result.actuals ) );
889 makeExprList( result.actuals, appExpr->get_args() );
890 PRINT(
891 std::cerr << "instantiate function success: " << appExpr << std::endl;
892 std::cerr << "need assertions:" << std::endl;
893 printAssertionSet( result.need, std::cerr, 8 );
894 )
895 inferParameters( result.need, result.have, newAlt, result.openVars, out );
896 }
897 }
898
899 void AlternativeFinder::visit( UntypedExpr *untypedExpr ) {
900 AlternativeFinder funcFinder( indexer, env );
901 funcFinder.findWithAdjustment( untypedExpr->get_function() );
902 // if there are no function alternatives, then proceeding is a waste of time.
903 if ( funcFinder.alternatives.empty() ) return;
904
905 std::vector< AlternativeFinder > argAlternatives;
906 findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
907 back_inserter( argAlternatives ) );
908
909 // take care of possible tuple assignments
910 // if not tuple assignment, assignment is taken care of as a normal function call
911 Tuples::handleTupleAssignment( *this, untypedExpr, argAlternatives );
912
913 // find function operators
914 static NameExpr *opExpr = new NameExpr( "?()" );
915 AlternativeFinder funcOpFinder( indexer, env );
916 // it's ok if there aren't any defined function ops
917 funcOpFinder.maybeFind( opExpr);
918 PRINT(
919 std::cerr << "known function ops:" << std::endl;
920 printAlts( funcOpFinder.alternatives, std::cerr, 1 );
921 )
922
923 AltList candidates;
924 SemanticError errors;
925 for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
926 try {
927 PRINT(
928 std::cerr << "working on alternative: " << std::endl;
929 func->print( std::cerr, 8 );
930 )
931 // check if the type is pointer to function
932 if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
933 if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
934 Alternative newFunc( *func );
935 referenceToRvalueConversion( newFunc.expr );
936 makeFunctionAlternatives( newFunc, function, argAlternatives,
937 std::back_inserter( candidates ) );
938 }
939 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
940 EqvClass eqvClass;
941 if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
942 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
943 Alternative newFunc( *func );
944 referenceToRvalueConversion( newFunc.expr );
945 makeFunctionAlternatives( newFunc, function, argAlternatives,
946 std::back_inserter( candidates ) );
947 } // if
948 } // if
949 }
950 } catch ( SemanticError &e ) {
951 errors.append( e );
952 }
953 } // for
954
955 // try each function operator ?() with each function alternative
956 if ( ! funcOpFinder.alternatives.empty() ) {
957 // add function alternatives to front of argument list
958 argAlternatives.insert( argAlternatives.begin(), std::move(funcFinder) );
959
960 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
961 funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
962 try {
963 // check if type is a pointer to function
964 if ( PointerType* pointer = dynamic_cast<PointerType*>(
965 funcOp->expr->get_result()->stripReferences() ) ) {
966 if ( FunctionType* function =
967 dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
968 Alternative newFunc( *funcOp );
969 referenceToRvalueConversion( newFunc.expr );
970 makeFunctionAlternatives( newFunc, function, argAlternatives,
971 std::back_inserter( candidates ) );
972 }
973 }
974 } catch ( SemanticError &e ) {
975 errors.append( e );
976 }
977 }
978 }
979
980 // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
981 if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
982
983 // compute conversionsion costs
984 for ( AltList::iterator withFunc = candidates.begin(); withFunc != candidates.end(); ++withFunc ) {
985 Cost cvtCost = computeApplicationConversionCost( *withFunc, indexer );
986
987 PRINT(
988 ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc->expr );
989 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
990 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
991 std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
992 std::cerr << "formals are:" << std::endl;
993 printAll( function->get_parameters(), std::cerr, 8 );
994 std::cerr << "actuals are:" << std::endl;
995 printAll( appExpr->get_args(), std::cerr, 8 );
996 std::cerr << "bindings are:" << std::endl;
997 withFunc->env.print( std::cerr, 8 );
998 std::cerr << "cost of conversion is:" << cvtCost << std::endl;
999 )
1000 if ( cvtCost != Cost::infinity ) {
1001 withFunc->cvtCost = cvtCost;
1002 alternatives.push_back( *withFunc );
1003 } // if
1004 } // for
1005
1006 candidates.clear();
1007 candidates.splice( candidates.end(), alternatives );
1008
1009 // use a new list so that alternatives are not examined by addAnonConversions twice.
1010 AltList winners;
1011 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
1012
1013 // function may return struct or union value, in which case we need to add alternatives for implicit
1014 // conversions to each of the anonymous members, must happen after findMinCost since anon conversions
1015 // are never the cheapest expression
1016 for ( const Alternative & alt : winners ) {
1017 addAnonConversions( alt );
1018 }
1019 alternatives.splice( alternatives.begin(), winners );
1020
1021 if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
1022 // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
1023 // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
1024 // forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
1025 // const char * x = "hello world";
1026 // unsigned char ch = x[0];
1027 // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
1028 // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
1029 // fix this issue in a more robust way.
1030 targetType = nullptr;
1031 visit( untypedExpr );
1032 }
1033 }
1034
1035 bool isLvalue( Expression *expr ) {
1036 // xxx - recurse into tuples?
1037 return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
1038 }
1039
1040 void AlternativeFinder::visit( AddressExpr *addressExpr ) {
1041 AlternativeFinder finder( indexer, env );
1042 finder.find( addressExpr->get_arg() );
1043 for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) {
1044 if ( isLvalue( i->expr ) ) {
1045 alternatives.push_back( Alternative( new AddressExpr( i->expr->clone() ), i->env, i->cost ) );
1046 } // if
1047 } // for
1048 }
1049
1050 void AlternativeFinder::visit( LabelAddressExpr * expr ) {
1051 alternatives.push_back( Alternative( expr->clone(), env, Cost::zero) );
1052 }
1053
1054 Expression * restructureCast( Expression * argExpr, Type * toType ) {
1055 if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
1056 // Argument expression is a tuple and the target type is not void and not a reference type.
1057 // Cast each member of the tuple to its corresponding target type, producing the tuple of those
1058 // cast expressions. If there are more components of the tuple than components in the target type,
1059 // then excess components do not come out in the result expression (but UniqueExprs ensure that
1060 // side effects will still be done).
1061 if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
1062 // expressions which may contain side effects require a single unique instance of the expression.
1063 argExpr = new UniqueExpr( argExpr );
1064 }
1065 std::list< Expression * > componentExprs;
1066 for ( unsigned int i = 0; i < toType->size(); i++ ) {
1067 // cast each component
1068 TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
1069 componentExprs.push_back( restructureCast( idx, toType->getComponent( i ) ) );
1070 }
1071 delete argExpr;
1072 assert( componentExprs.size() > 0 );
1073 // produce the tuple of casts
1074 return new TupleExpr( componentExprs );
1075 } else {
1076 // handle normally
1077 return new CastExpr( argExpr, toType->clone() );
1078 }
1079 }
1080
1081 void AlternativeFinder::visit( CastExpr *castExpr ) {
1082 Type *& toType = castExpr->get_result();
1083 assert( toType );
1084 toType = resolveTypeof( toType, indexer );
1085 SymTab::validateType( toType, &indexer );
1086 adjustExprType( toType, env, indexer );
1087
1088 AlternativeFinder finder( indexer, env );
1089 finder.targetType = toType;
1090 finder.findWithAdjustment( castExpr->get_arg() );
1091
1092 AltList candidates;
1093 for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) {
1094 AssertionSet needAssertions, haveAssertions;
1095 OpenVarSet openVars;
1096
1097 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
1098 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
1099 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
1100 // to.
1101 int discardedValues = i->expr->get_result()->size() - castExpr->get_result()->size();
1102 if ( discardedValues < 0 ) continue;
1103 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1104 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1105 // unification run for side-effects
1106 unify( castExpr->get_result(), i->expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer );
1107 Cost thisCost = castCost( i->expr->get_result(), castExpr->get_result(), indexer, i->env );
1108 PRINT(
1109 std::cerr << "working on cast with result: " << castExpr->result << std::endl;
1110 std::cerr << "and expr type: " << i->expr->result << std::endl;
1111 std::cerr << "env: " << i->env << std::endl;
1112 )
1113 if ( thisCost != Cost::infinity ) {
1114 PRINT(
1115 std::cerr << "has finite cost." << std::endl;
1116 )
1117 // count one safe conversion for each value that is thrown away
1118 thisCost.incSafe( discardedValues );
1119 Alternative newAlt( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost );
1120 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
1121 } // if
1122 } // for
1123
1124 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1125 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
1126 // selects first based on argument cost, then on conversion cost.
1127 AltList minArgCost;
1128 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1129 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1130 }
1131
1132 void AlternativeFinder::visit( VirtualCastExpr * castExpr ) {
1133 assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
1134 AlternativeFinder finder( indexer, env );
1135 // don't prune here, since it's guaranteed all alternatives will have the same type
1136 finder.findWithoutPrune( castExpr->get_arg() );
1137 for ( Alternative & alt : finder.alternatives ) {
1138 alternatives.push_back( Alternative(
1139 new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
1140 alt.env, alt.cost ) );
1141 }
1142 }
1143
1144 void AlternativeFinder::visit( UntypedMemberExpr *memberExpr ) {
1145 AlternativeFinder funcFinder( indexer, env );
1146 funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
1147 for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
1148 // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
1149 std::unique_ptr<Expression> aggrExpr( agg->expr->clone() );
1150 Type * aggrType = aggrExpr->get_result();
1151 if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
1152 aggrType = aggrType->stripReferences();
1153 aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
1154 }
1155 // find member of the given type
1156 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
1157 addAggMembers( structInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
1158 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
1159 addAggMembers( unionInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
1160 } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
1161 addTupleMembers( tupleType, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
1162 } // if
1163 } // for
1164 }
1165
1166 void AlternativeFinder::visit( MemberExpr *memberExpr ) {
1167 alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
1168 }
1169
1170 void AlternativeFinder::visit( NameExpr *nameExpr ) {
1171 std::list< DeclarationWithType* > declList;
1172 indexer.lookupId( nameExpr->get_name(), declList );
1173 PRINT( std::cerr << "nameExpr is " << nameExpr->get_name() << std::endl; )
1174 for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) {
1175 VariableExpr newExpr( *i );
1176 alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
1177 PRINT(
1178 std::cerr << "decl is ";
1179 (*i)->print( std::cerr );
1180 std::cerr << std::endl;
1181 std::cerr << "newExpr is ";
1182 newExpr.print( std::cerr );
1183 std::cerr << std::endl;
1184 )
1185 renameTypes( alternatives.back().expr );
1186 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
1187 } // for
1188 }
1189
1190 void AlternativeFinder::visit( VariableExpr *variableExpr ) {
1191 // not sufficient to clone here, because variable's type may have changed
1192 // since the VariableExpr was originally created.
1193 alternatives.push_back( Alternative( new VariableExpr( variableExpr->get_var() ), env, Cost::zero ) );
1194 }
1195
1196 void AlternativeFinder::visit( ConstantExpr *constantExpr ) {
1197 alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
1198 }
1199
1200 void AlternativeFinder::visit( SizeofExpr *sizeofExpr ) {
1201 if ( sizeofExpr->get_isType() ) {
1202 Type * newType = sizeofExpr->get_type()->clone();
1203 alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1204 } else {
1205 // find all alternatives for the argument to sizeof
1206 AlternativeFinder finder( indexer, env );
1207 finder.find( sizeofExpr->get_expr() );
1208 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1209 AltList winners;
1210 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1211 if ( winners.size() != 1 ) {
1212 throw SemanticError( "Ambiguous expression in sizeof operand: ", sizeofExpr->get_expr() );
1213 } // if
1214 // return the lowest cost alternative for the argument
1215 Alternative &choice = winners.front();
1216 referenceToRvalueConversion( choice.expr );
1217 alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1218 } // if
1219 }
1220
1221 void AlternativeFinder::visit( AlignofExpr *alignofExpr ) {
1222 if ( alignofExpr->get_isType() ) {
1223 Type * newType = alignofExpr->get_type()->clone();
1224 alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1225 } else {
1226 // find all alternatives for the argument to sizeof
1227 AlternativeFinder finder( indexer, env );
1228 finder.find( alignofExpr->get_expr() );
1229 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1230 AltList winners;
1231 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1232 if ( winners.size() != 1 ) {
1233 throw SemanticError( "Ambiguous expression in alignof operand: ", alignofExpr->get_expr() );
1234 } // if
1235 // return the lowest cost alternative for the argument
1236 Alternative &choice = winners.front();
1237 referenceToRvalueConversion( choice.expr );
1238 alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1239 } // if
1240 }
1241
1242 template< typename StructOrUnionType >
1243 void AlternativeFinder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
1244 std::list< Declaration* > members;
1245 aggInst->lookup( name, members );
1246 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1247 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
1248 alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
1249 renameTypes( alternatives.back().expr );
1250 } else {
1251 assert( false );
1252 }
1253 }
1254 }
1255
1256 void AlternativeFinder::visit( UntypedOffsetofExpr *offsetofExpr ) {
1257 AlternativeFinder funcFinder( indexer, env );
1258 // xxx - resolveTypeof?
1259 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
1260 addOffsetof( structInst, offsetofExpr->get_member() );
1261 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
1262 addOffsetof( unionInst, offsetofExpr->get_member() );
1263 }
1264 }
1265
1266 void AlternativeFinder::visit( OffsetofExpr *offsetofExpr ) {
1267 alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
1268 }
1269
1270 void AlternativeFinder::visit( OffsetPackExpr *offsetPackExpr ) {
1271 alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
1272 }
1273
1274 void AlternativeFinder::resolveAttr( DeclarationWithType *funcDecl, FunctionType *function, Type *argType, const TypeEnvironment &env ) {
1275 // assume no polymorphism
1276 // assume no implicit conversions
1277 assert( function->get_parameters().size() == 1 );
1278 PRINT(
1279 std::cerr << "resolvAttr: funcDecl is ";
1280 funcDecl->print( std::cerr );
1281 std::cerr << " argType is ";
1282 argType->print( std::cerr );
1283 std::cerr << std::endl;
1284 )
1285 if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1286 alternatives.push_back( Alternative( new AttrExpr( new VariableExpr( funcDecl ), argType->clone() ), env, Cost::zero ) );
1287 for ( std::list< DeclarationWithType* >::iterator i = function->get_returnVals().begin(); i != function->get_returnVals().end(); ++i ) {
1288 alternatives.back().expr->set_result( (*i)->get_type()->clone() );
1289 } // for
1290 } // if
1291 }
1292
1293 void AlternativeFinder::visit( AttrExpr *attrExpr ) {
1294 // assume no 'pointer-to-attribute'
1295 NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1296 assert( nameExpr );
1297 std::list< DeclarationWithType* > attrList;
1298 indexer.lookupId( nameExpr->get_name(), attrList );
1299 if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
1300 for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
1301 // check if the type is function
1302 if ( FunctionType *function = dynamic_cast< FunctionType* >( (*i)->get_type() ) ) {
1303 // assume exactly one parameter
1304 if ( function->get_parameters().size() == 1 ) {
1305 if ( attrExpr->get_isType() ) {
1306 resolveAttr( *i, function, attrExpr->get_type(), env );
1307 } else {
1308 AlternativeFinder finder( indexer, env );
1309 finder.find( attrExpr->get_expr() );
1310 for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
1311 if ( choice->expr->get_result()->size() == 1 ) {
1312 resolveAttr(*i, function, choice->expr->get_result(), choice->env );
1313 } // fi
1314 } // for
1315 } // if
1316 } // if
1317 } // if
1318 } // for
1319 } else {
1320 for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
1321 VariableExpr newExpr( *i );
1322 alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
1323 renameTypes( alternatives.back().expr );
1324 } // for
1325 } // if
1326 }
1327
1328 void AlternativeFinder::visit( LogicalExpr *logicalExpr ) {
1329 AlternativeFinder firstFinder( indexer, env );
1330 firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
1331 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
1332 AlternativeFinder secondFinder( indexer, first->env );
1333 secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
1334 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
1335 LogicalExpr *newExpr = new LogicalExpr( first->expr->clone(), second->expr->clone(), logicalExpr->get_isAnd() );
1336 alternatives.push_back( Alternative( newExpr, second->env, first->cost + second->cost ) );
1337 }
1338 }
1339 }
1340
1341 void AlternativeFinder::visit( ConditionalExpr *conditionalExpr ) {
1342 // find alternatives for condition
1343 AlternativeFinder firstFinder( indexer, env );
1344 firstFinder.findWithAdjustment( conditionalExpr->get_arg1() );
1345 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
1346 // find alternatives for true expression
1347 AlternativeFinder secondFinder( indexer, first->env );
1348 secondFinder.findWithAdjustment( conditionalExpr->get_arg2() );
1349 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
1350 // find alterantives for false expression
1351 AlternativeFinder thirdFinder( indexer, second->env );
1352 thirdFinder.findWithAdjustment( conditionalExpr->get_arg3() );
1353 for ( AltList::const_iterator third = thirdFinder.alternatives.begin(); third != thirdFinder.alternatives.end(); ++third ) {
1354 // unify true and false types, then infer parameters to produce new alternatives
1355 OpenVarSet openVars;
1356 AssertionSet needAssertions, haveAssertions;
1357 Alternative newAlt( 0, third->env, first->cost + second->cost + third->cost );
1358 Type* commonType = nullptr;
1359 if ( unify( second->expr->get_result(), third->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1360 ConditionalExpr *newExpr = new ConditionalExpr( first->expr->clone(), second->expr->clone(), third->expr->clone() );
1361 newExpr->set_result( commonType ? commonType : second->expr->get_result()->clone() );
1362 // convert both options to the conditional result type
1363 newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
1364 newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
1365 newAlt.expr = newExpr;
1366 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1367 } // if
1368 } // for
1369 } // for
1370 } // for
1371 }
1372
1373 void AlternativeFinder::visit( CommaExpr *commaExpr ) {
1374 TypeEnvironment newEnv( env );
1375 Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
1376 AlternativeFinder secondFinder( indexer, newEnv );
1377 secondFinder.findWithAdjustment( commaExpr->get_arg2() );
1378 for ( AltList::const_iterator alt = secondFinder.alternatives.begin(); alt != secondFinder.alternatives.end(); ++alt ) {
1379 alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt->expr->clone() ), alt->env, alt->cost ) );
1380 } // for
1381 delete newFirstArg;
1382 }
1383
1384 void AlternativeFinder::visit( RangeExpr * rangeExpr ) {
1385 // resolve low and high, accept alternatives whose low and high types unify
1386 AlternativeFinder firstFinder( indexer, env );
1387 firstFinder.findWithAdjustment( rangeExpr->get_low() );
1388 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
1389 AlternativeFinder secondFinder( indexer, first->env );
1390 secondFinder.findWithAdjustment( rangeExpr->get_high() );
1391 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
1392 OpenVarSet openVars;
1393 AssertionSet needAssertions, haveAssertions;
1394 Alternative newAlt( 0, second->env, first->cost + second->cost );
1395 Type* commonType = nullptr;
1396 if ( unify( first->expr->get_result(), second->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1397 RangeExpr *newExpr = new RangeExpr( first->expr->clone(), second->expr->clone() );
1398 newExpr->set_result( commonType ? commonType : first->expr->get_result()->clone() );
1399 newAlt.expr = newExpr;
1400 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1401 } // if
1402 } // for
1403 } // for
1404 }
1405
1406 void AlternativeFinder::visit( UntypedTupleExpr *tupleExpr ) {
1407 std::list< AlternativeFinder > subExprAlternatives;
1408 findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), back_inserter( subExprAlternatives ) );
1409 std::list< AltList > possibilities;
1410 combos( subExprAlternatives.begin(), subExprAlternatives.end(), back_inserter( possibilities ) );
1411 for ( std::list< AltList >::const_iterator i = possibilities.begin(); i != possibilities.end(); ++i ) {
1412 std::list< Expression * > exprs;
1413 makeExprList( *i, exprs );
1414
1415 TypeEnvironment compositeEnv;
1416 simpleCombineEnvironments( i->begin(), i->end(), compositeEnv );
1417 alternatives.push_back( Alternative( new TupleExpr( exprs ) , compositeEnv, sumCost( *i ) ) );
1418 } // for
1419 }
1420
1421 void AlternativeFinder::visit( TupleExpr *tupleExpr ) {
1422 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1423 }
1424
1425 void AlternativeFinder::visit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
1426 alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
1427 }
1428
1429 void AlternativeFinder::visit( ConstructorExpr * ctorExpr ) {
1430 AlternativeFinder finder( indexer, env );
1431 // don't prune here, since it's guaranteed all alternatives will have the same type
1432 // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
1433 finder.findWithoutPrune( ctorExpr->get_callExpr() );
1434 for ( Alternative & alt : finder.alternatives ) {
1435 alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
1436 }
1437 }
1438
1439 void AlternativeFinder::visit( TupleIndexExpr *tupleExpr ) {
1440 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1441 }
1442
1443 void AlternativeFinder::visit( TupleAssignExpr *tupleAssignExpr ) {
1444 alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
1445 }
1446
1447 void AlternativeFinder::visit( UniqueExpr *unqExpr ) {
1448 AlternativeFinder finder( indexer, env );
1449 finder.findWithAdjustment( unqExpr->get_expr() );
1450 for ( Alternative & alt : finder.alternatives ) {
1451 // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
1452 UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
1453 alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
1454 }
1455 }
1456
1457 void AlternativeFinder::visit( StmtExpr *stmtExpr ) {
1458 StmtExpr * newStmtExpr = stmtExpr->clone();
1459 ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
1460 // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
1461 alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
1462 }
1463
1464 void AlternativeFinder::visit( UntypedInitExpr *initExpr ) {
1465 // handle each option like a cast
1466 AltList candidates;
1467 PRINT( std::cerr << "untyped init expr: " << initExpr << std::endl; )
1468 // O(N^2) checks of d-types with e-types
1469 for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
1470 Type * toType = resolveTypeof( initAlt.type->clone(), indexer );
1471 SymTab::validateType( toType, &indexer );
1472 adjustExprType( toType, env, indexer );
1473 // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
1474 // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
1475 // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
1476 AlternativeFinder finder( indexer, env );
1477 finder.targetType = toType;
1478 finder.findWithAdjustment( initExpr->get_expr() );
1479 for ( Alternative & alt : finder.get_alternatives() ) {
1480 TypeEnvironment newEnv( alt.env );
1481 AssertionSet needAssertions, haveAssertions;
1482 OpenVarSet openVars; // find things in env that don't have a "representative type" and claim those are open vars?
1483 PRINT( std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; )
1484 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
1485 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
1486 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
1487 // to.
1488 int discardedValues = alt.expr->get_result()->size() - toType->size();
1489 if ( discardedValues < 0 ) continue;
1490 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1491 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1492 // unification run for side-effects
1493 unify( toType, alt.expr->get_result(), newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
1494
1495 Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );
1496 if ( thisCost != Cost::infinity ) {
1497 // count one safe conversion for each value that is thrown away
1498 thisCost.incSafe( discardedValues );
1499 Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
1500 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
1501 }
1502 }
1503 }
1504
1505 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1506 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
1507 // selects first based on argument cost, then on conversion cost.
1508 AltList minArgCost;
1509 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1510 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1511 }
1512} // namespace ResolvExpr
1513
1514// Local Variables: //
1515// tab-width: 4 //
1516// mode: c++ //
1517// compile-command: "make install" //
1518// End: //
Note: See TracBrowser for help on using the repository browser.