source: src/ResolvExpr/AlternativeFinder.cc@ 85d340d

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 85d340d was 954ef5b, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Fix array-to-pointer decay to only decay one level

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