source: src/ResolvExpr/AlternativeFinder.cc@ d551d0a

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 d551d0a was d551d0a, checked in by Aaron Moss <a3moss@…>, 8 years ago

Fix one use-after-free in resolver refactor

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