source: src/ResolvExpr/AlternativeFinder.cc@ bd4f2e9

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 stuck-waitfor-destruct with_gc
Last change on this file since bd4f2e9 was bd4f2e9, checked in by Aaron Moss <a3moss@…>, 8 years ago

Switch AltList to std::vector from std::list

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