source: src/ResolvExpr/AlternativeFinder.cc@ 121ac13

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 121ac13 was b0837e4, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Minor cleanup in conversion code

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