source: src/ResolvExpr/AlternativeFinder.cc@ 1755226

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 1755226 was 33a25f9, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Remove visitor feature from Indexer

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