Changeset eef8dfb for src/ResolvExpr
- Timestamp:
- Jan 7, 2021, 2:55:57 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 58fe85a
- Parents:
- bdfc032 (diff), 44e37ef (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- src/ResolvExpr
- Files:
-
- 31 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/AdjustExprType.cc
rbdfc032 reef8dfb 100 100 101 101 namespace { 102 struct AdjustExprType_new final : public ast::WithShortCircuiting { 102 class AdjustExprType_new final : public ast::WithShortCircuiting { 103 const ast::SymbolTable & symtab; 104 public: 103 105 const ast::TypeEnvironment & tenv; 104 const ast::SymbolTable & symtab;105 106 106 107 AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 107 : tenv( e ), symtab( syms) {}108 : symtab( syms ), tenv( e ) {} 108 109 109 void pre mutate( const ast::VoidType * ) { visit_children = false; }110 void pre mutate( const ast::BasicType * ) { visit_children = false; }111 void pre mutate( const ast::PointerType * ) { visit_children = false; }112 void pre mutate( const ast::ArrayType * ) { visit_children = false; }113 void pre mutate( const ast::FunctionType * ) { visit_children = false; }114 void pre mutate( const ast::StructInstType * ) { visit_children = false; }115 void pre mutate( const ast::UnionInstType * ) { visit_children = false; }116 void pre mutate( const ast::EnumInstType * ) { visit_children = false; }117 void pre mutate( const ast::TraitInstType * ) { visit_children = false; }118 void pre mutate( const ast::TypeInstType * ) { visit_children = false; }119 void pre mutate( const ast::TupleType * ) { visit_children = false; }120 void pre mutate( const ast::VarArgsType * ) { visit_children = false; }121 void pre mutate( const ast::ZeroType * ) { visit_children = false; }122 void pre mutate( const ast::OneType * ) { visit_children = false; }110 void previsit( const ast::VoidType * ) { visit_children = false; } 111 void previsit( const ast::BasicType * ) { visit_children = false; } 112 void previsit( const ast::PointerType * ) { visit_children = false; } 113 void previsit( const ast::ArrayType * ) { visit_children = false; } 114 void previsit( const ast::FunctionType * ) { visit_children = false; } 115 void previsit( const ast::StructInstType * ) { visit_children = false; } 116 void previsit( const ast::UnionInstType * ) { visit_children = false; } 117 void previsit( const ast::EnumInstType * ) { visit_children = false; } 118 void previsit( const ast::TraitInstType * ) { visit_children = false; } 119 void previsit( const ast::TypeInstType * ) { visit_children = false; } 120 void previsit( const ast::TupleType * ) { visit_children = false; } 121 void previsit( const ast::VarArgsType * ) { visit_children = false; } 122 void previsit( const ast::ZeroType * ) { visit_children = false; } 123 void previsit( const ast::OneType * ) { visit_children = false; } 123 124 124 const ast::Type * post mutate( const ast::ArrayType * at ) {125 const ast::Type * postvisit( const ast::ArrayType * at ) { 125 126 return new ast::PointerType{ at->base, at->qualifiers }; 126 127 } 127 128 128 const ast::Type * post mutate( const ast::FunctionType * ft ) {129 const ast::Type * postvisit( const ast::FunctionType * ft ) { 129 130 return new ast::PointerType{ ft }; 130 131 } 131 132 132 const ast::Type * post mutate( const ast::TypeInstType * inst ) {133 const ast::Type * postvisit( const ast::TypeInstType * inst ) { 133 134 // replace known function-type-variables with pointer-to-function 134 if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name) ) {135 if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) { 135 136 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) { 136 137 return new ast::PointerType{ inst }; -
src/ResolvExpr/AlternativeFinder.cc
rbdfc032 reef8dfb 131 131 132 132 void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) { 133 Indenter indent = { indentAmt }; 134 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) { 135 i->print( os, indent ); 136 os << std::endl; 133 std::vector<std::string> sorted; 134 sorted.reserve(list.size()); 135 for(const auto & c : list) { 136 std::stringstream ss; 137 c.print( ss, indentAmt ); 138 sorted.push_back(ss.str()); 139 } 140 141 std::sort(sorted.begin(), sorted.end()); 142 143 for ( const auto & s : sorted ) { 144 os << s << std::endl; 137 145 } 138 146 } … … 251 259 SemanticError( expr, "No reasonable alternatives for expression " ); 252 260 } 253 if ( mode. satisfyAssns || mode.prune ) {261 if ( mode.prune ) { 254 262 // trim candidates just to those where the assertions resolve 255 263 // - necessary pre-requisite to pruning … … 1216 1224 unify( castExpr->result, alt.expr->result, alt.env, needAssertions, 1217 1225 haveAssertions, openVars, indexer ); 1218 Cost thisCost = castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(), 1219 indexer, alt.env ); 1226 Cost thisCost = 1227 castExpr->isGenerated 1228 ? conversionCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(), indexer, alt.env ) 1229 : castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(), indexer, alt.env ); 1220 1230 PRINT( 1221 1231 std::cerr << "working on cast with result: " << castExpr->result << std::endl; … … 1292 1302 1293 1303 try { 1294 // Attempt 1 : turn (thread&)X into ( thread_desc&)X.__thrd1304 // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd 1295 1305 // Clone is purely for memory management 1296 1306 std::unique_ptr<Expression> tech1 { new UntypedMemberExpr(new NameExpr(castExpr->concrete_target.field), castExpr->arg->clone()) }; … … 1303 1313 } catch(SemanticErrorException & ) {} 1304 1314 1305 // Fallback : turn (thread&)X into ( thread_desc&)get_thread(X)1315 // Fallback : turn (thread&)X into ($thread&)get_thread(X) 1306 1316 std::unique_ptr<Expression> fallback { UntypedExpr::createDeref( new UntypedExpr(new NameExpr(castExpr->concrete_target.getter), { castExpr->arg->clone() })) }; 1307 1317 // don't prune here, since it's guaranteed all alternatives will have the same type … … 1698 1708 1699 1709 // unification run for side-effects 1700 unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer ); 1710 bool canUnify = unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer ); 1711 (void) canUnify; 1701 1712 // xxx - do some inspecting on this line... why isn't result bound to initAlt.type? 1702 1713 1703 Cost thisCost = c astCost( alt.expr->result, toType, alt.expr->get_lvalue(),1714 Cost thisCost = computeConversionCost( alt.expr->result, toType, alt.expr->get_lvalue(), 1704 1715 indexer, newEnv ); 1716 1717 PRINT( 1718 Cost legacyCost = castCost( alt.expr->result, toType, alt.expr->get_lvalue(), 1719 indexer, newEnv ); 1720 std::cerr << "Considering initialization:"; 1721 std::cerr << std::endl << " FROM: "; alt.expr->result->print(std::cerr); 1722 std::cerr << std::endl << " TO: "; toType ->print(std::cerr); 1723 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed"); 1724 std::cerr << std::endl << " Legacy cost " << legacyCost; 1725 std::cerr << std::endl << " New cost " << thisCost; 1726 std::cerr << std::endl; 1727 ) 1728 1705 1729 if ( thisCost != Cost::infinity ) { 1706 1730 // count one safe conversion for each value that is thrown away -
src/ResolvExpr/Candidate.cpp
rbdfc032 reef8dfb 41 41 42 42 void print( std::ostream & os, const CandidateList & cands, Indenter indent ) { 43 for ( const CandidateRef & cand : cands ) { 44 print( os, *cand, indent ); 45 os << std::endl; 43 std::vector<std::string> sorted; 44 sorted.reserve(cands.size()); 45 for(const auto & c : cands) { 46 std::stringstream ss; 47 print( ss, *c, indent ); 48 sorted.push_back(ss.str()); 49 } 50 51 std::sort(sorted.begin(), sorted.end()); 52 53 for ( const auto & s : sorted ) { 54 os << s << std::endl; 46 55 } 47 56 } -
src/ResolvExpr/Candidate.hpp
rbdfc032 reef8dfb 51 51 52 52 Candidate( const ast::Expr * x, const ast::TypeEnvironment & e ) 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {} 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() { 54 assert(x->result); 55 } 54 56 55 57 Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero ) 56 58 : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ), 57 need( o.need ) {} 59 need( o.need ) { 60 assert(x->result); 61 } 58 62 59 63 Candidate( 60 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 64 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 61 65 const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero ) 62 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {} 66 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) { 67 assert(x->result); 68 } 63 69 64 70 Candidate( … … 66 72 ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero ) 67 73 : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ), 68 need( n.begin(), n.end() ) {} 74 need( n.begin(), n.end() ) { 75 assert(x->result); 76 } 69 77 }; 70 78 -
src/ResolvExpr/CandidateFinder.cpp
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 14:55:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 43 43 #include "SymTab/Validate.h" // for validateType 44 44 #include "Tuples/Tuples.h" // for handleTupleAssignment 45 #include "InitTweak/InitTweak.h" // for getPointerBase 46 47 #include "Common/Stats/Counter.h" 45 48 46 49 #define PRINT( text ) if ( resolvep ) { text } … … 54 57 return new ast::CastExpr{ expr, expr->result->stripReferences() }; 55 58 } 56 59 57 60 return expr; 58 61 } … … 61 64 UniqueId globalResnSlot = 0; 62 65 63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,65 const ast:: TypeEnvironment & env66 Cost computeConversionCost( 67 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 68 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 66 69 ) { 67 70 PRINT( … … 74 77 std::cerr << std::endl; 75 78 ) 76 Cost convCost = conversionCost( argType, paramType, symtab, env );79 Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env ); 77 80 PRINT( 78 81 std::cerr << std::endl << "cost is " << convCost << std::endl; … … 107 110 108 111 /// Computes conversion cost for a given expression to a given type 109 const ast::Expr * computeExpressionConversionCost( 110 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 112 const ast::Expr * computeExpressionConversionCost( 113 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 111 114 ) { 112 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env ); 115 Cost convCost = computeConversionCost( 116 arg->result, paramType, arg->get_lvalue(), symtab, env ); 113 117 outCost += convCost; 114 118 115 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 116 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 119 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 120 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 117 121 // infer parameters and this does not currently work for the reason stated below 118 122 Cost tmpCost = convCost; … … 123 127 return new ast::CastExpr{ arg, newType }; 124 128 125 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 126 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 129 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 130 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 127 131 // once this is fixed it should be possible to resolve the cast. 128 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 129 // but it shouldn't be because this makes the conversion from DT* to DT* since 132 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 133 // but it shouldn't be because this makes the conversion from DT* to DT* since 130 134 // commontype(zero_t, DT*) is DT*, rather than nothing 131 135 132 136 // CandidateFinder finder{ symtab, env }; 133 137 // finder.find( arg, ResolvMode::withAdjustment() ); 134 // assertf( finder.candidates.size() > 0, 138 // assertf( finder.candidates.size() > 0, 135 139 // "Somehow castable expression failed to find alternatives." ); 136 // assertf( finder.candidates.size() == 1, 140 // assertf( finder.candidates.size() == 1, 137 141 // "Somehow got multiple alternatives for known cast expression." ); 138 142 // return finder.candidates.front()->expr; … … 143 147 144 148 /// Computes conversion cost for a given candidate 145 Cost computeApplicationConversionCost( 146 CandidateRef cand, const ast::SymbolTable & symtab 149 Cost computeApplicationConversionCost( 150 CandidateRef cand, const ast::SymbolTable & symtab 147 151 ) { 148 152 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); … … 167 171 if ( function->isVarArgs ) { 168 172 convCost.incUnsafe(); 169 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 173 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 174 << convCost << std::endl; ; ) 171 175 // convert reference-typed expressions into value-typed expressions 172 cand->expr = ast::mutate_field_index( 173 appExpr, &ast::ApplicationExpr::args, i, 176 cand->expr = ast::mutate_field_index( 177 appExpr, &ast::ApplicationExpr::args, i, 174 178 referenceToRvalueConversion( args[i], convCost ) ); 175 179 continue; … … 180 184 // Default arguments should be free - don't include conversion cost. 181 185 // Unwrap them here because they are not relevant to the rest of the system 182 cand->expr = ast::mutate_field_index( 186 cand->expr = ast::mutate_field_index( 183 187 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 184 188 ++param; … … 187 191 188 192 // mark conversion cost and also specialization cost of param type 189 const ast::Type * paramType = (*param)->get_type();190 cand->expr = ast::mutate_field_index( 191 appExpr, &ast::ApplicationExpr::args, i, 192 computeExpressionConversionCost( 193 args[i], paramType, symtab, cand->env, convCost ) );194 convCost.decSpec( specCost( paramType) );193 // const ast::Type * paramType = (*param)->get_type(); 194 cand->expr = ast::mutate_field_index( 195 appExpr, &ast::ApplicationExpr::args, i, 196 computeExpressionConversionCost( 197 args[i], *param, symtab, cand->env, convCost ) ); 198 convCost.decSpec( specCost( *param ) ); 195 199 ++param; // can't be in for-loop update because of the continue 196 200 } … … 198 202 if ( param != params.end() ) return Cost::infinity; 199 203 200 // specialization cost of return types can't be accounted for directly, it disables 204 // specialization cost of return types can't be accounted for directly, it disables 201 205 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 202 206 // … … 208 212 // mark type variable and specialization cost of forall clause 209 213 convCost.incVar( function->forall.size() ); 210 for ( const ast::TypeDecl * td : function->forall ) { 211 convCost.decSpec( td->assertions.size() ); 212 } 214 convCost.decSpec( function->assertions.size() ); 213 215 214 216 return convCost; 215 217 } 216 218 217 void makeUnifiableVars( 218 const ast:: ParameterizedType * type, ast::OpenVarSet & unifiableVars,219 ast::AssertionSet & need 219 void makeUnifiableVars( 220 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars, 221 ast::AssertionSet & need 220 222 ) { 221 for ( const ast::TypeDecl *tyvar : type->forall ) {222 unifiableVars[ tyvar->name ] = ast::TypeDecl::Data{ tyvar};223 for ( const ast::DeclWithType * assn : tyvar->assertions ) {224 need[ assn ].isUsed = true;225 }223 for ( auto & tyvar : type->forall ) { 224 unifiableVars[ *tyvar ] = ast::TypeDecl::Data{ tyvar->base }; 225 } 226 for ( auto & assn : type->assertions ) { 227 need[ assn ].isUsed = true; 226 228 } 227 229 } … … 254 256 255 257 ArgPack() 256 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 258 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 259 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 258 259 ArgPack( 260 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 260 261 ArgPack( 262 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 261 263 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 262 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 264 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 265 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 264 266 265 267 ArgPack( 266 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 267 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 268 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 268 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 269 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 270 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 269 271 unsigned nextExpl = 0, unsigned explAlt = 0 ) 270 272 : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ), 271 273 have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 272 274 nextExpl( nextExpl ), explAlt( explAlt ) {} 273 275 274 276 ArgPack( 275 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 277 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 278 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 277 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 278 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 279 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 280 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 279 281 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 280 282 281 283 /// true if this pack is in the middle of an exploded argument 282 284 bool hasExpl() const { return nextExpl > 0; } … … 286 288 return args[ nextArg-1 ][ explAlt ]; 287 289 } 288 290 289 291 /// Ends a tuple expression, consolidating the appropriate args 290 292 void endTuple( const std::vector< ArgPack > & packs ) { … … 307 309 308 310 /// Instantiates an argument to match a parameter, returns false if no matching results left 309 bool instantiateArgument( 310 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 311 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 312 unsigned nTuples = 0 311 bool instantiateArgument( 312 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 313 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 314 unsigned nTuples = 0 313 315 ) { 314 316 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { … … 318 320 // xxx - dropping initializer changes behaviour from previous, but seems correct 319 321 // ^^^ need to handle the case where a tuple has a default argument 320 if ( ! instantiateArgument( 322 if ( ! instantiateArgument( 321 323 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 322 324 nTuples = 0; … … 329 331 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 330 332 // paramType is a ttype, consumes all remaining arguments 331 333 332 334 // completed tuples; will be spliced to end of results to finish 333 335 std::vector< ArgPack > finalResults{}; … … 342 344 for ( std::size_t i = genStart; i < genEnd; ++i ) { 343 345 unsigned nextArg = results[i].nextArg; 344 346 345 347 // use next element of exploded tuple if present 346 348 if ( results[i].hasExpl() ) { … … 352 354 results.emplace_back( 353 355 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 354 copy( results[i].need ), copy( results[i].have ), 356 copy( results[i].need ), copy( results[i].have ), 355 357 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 356 358 results[i].explAlt ); … … 370 372 // push empty tuple expression 371 373 newResult.parent = i; 372 std::vector< ast::ptr< ast::Expr > > emptyList; 373 newResult.expr = 374 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) }; 374 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} }; 375 375 argType = newResult.expr->result; 376 376 } else { … … 400 400 401 401 // check unification for ttype before adding to final 402 if ( 403 unify( 402 if ( 403 unify( 404 404 ttype, argType, newResult.env, newResult.need, newResult.have, 405 newResult.open, symtab ) 405 newResult.open, symtab ) 406 406 ) { 407 407 finalResults.emplace_back( move( newResult ) ); … … 424 424 if ( expl.exprs.empty() ) { 425 425 results.emplace_back( 426 results[i], move( env ), copy( results[i].need ), 426 results[i], move( env ), copy( results[i].need ), 427 427 copy( results[i].have ), move( open ), nextArg + 1, expl.cost ); 428 428 429 429 continue; 430 430 } … … 432 432 // add new result 433 433 results.emplace_back( 434 i, expl.exprs.front(), move( env ), copy( results[i].need ), 435 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 434 i, expl.exprs.front(), move( env ), copy( results[i].need ), 435 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 436 436 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 437 437 } … … 479 479 480 480 results.emplace_back( 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 482 482 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 483 483 } … … 495 495 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 496 496 results.emplace_back( 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 498 498 move( need ), move( have ), move( open ), nextArg, nTuples ); 499 499 } … … 517 517 if ( expl.exprs.empty() ) { 518 518 results.emplace_back( 519 results[i], move( env ), move( need ), move( have ), move( open ), 519 results[i], move( env ), move( need ), move( have ), move( open ), 520 520 nextArg + 1, expl.cost ); 521 521 522 522 continue; 523 523 } … … 539 539 // add new result 540 540 results.emplace_back( 541 i, expr, move( env ), move( need ), move( have ), move( open ), 541 i, expr, move( env ), move( need ), move( have ), move( open ), 542 542 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 543 543 } … … 548 548 genStart = genEnd; 549 549 550 return genEnd != results.size(); 550 return genEnd != results.size(); // were any new results added? 551 551 } 552 552 553 553 /// Generate a cast expression from `arg` to `toType` 554 const ast::Expr * restructureCast( 554 const ast::Expr * restructureCast( 555 555 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 556 556 ) { 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 561 561 ) { 562 // Argument is a tuple and the target type is neither void nor a reference. Cast each 563 // member of the tuple to its corresponding target type, producing the tuple of those 564 // cast expressions. If there are more components of the tuple than components in the 565 // target type, then excess components do not come out in the result expression (but 562 // Argument is a tuple and the target type is neither void nor a reference. Cast each 563 // member of the tuple to its corresponding target type, producing the tuple of those 564 // cast expressions. If there are more components of the tuple than components in the 565 // target type, then excess components do not come out in the result expression (but 566 566 // UniqueExpr ensures that the side effects will still be produced) 567 567 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 568 // expressions which may contain side effects require a single unique instance of 568 // expressions which may contain side effects require a single unique instance of 569 569 // the expression 570 570 arg = new ast::UniqueExpr{ arg->location, arg }; … … 574 574 // cast each component 575 575 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 576 components.emplace_back( 576 components.emplace_back( 577 577 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 578 578 } … … 594 594 595 595 /// Actually visits expressions to find their candidate interpretations 596 struct Finder final : public ast::WithShortCircuiting { 596 class Finder final : public ast::WithShortCircuiting { 597 const ast::SymbolTable & symtab; 598 public: 599 static size_t traceId; 597 600 CandidateFinder & selfFinder; 598 const ast::SymbolTable & symtab;599 601 CandidateList & candidates; 600 602 const ast::TypeEnvironment & tenv; 601 603 ast::ptr< ast::Type > & targetType; 602 604 605 enum Errors { 606 NotFound, 607 NoMatch, 608 ArgsToFew, 609 ArgsToMany, 610 RetsToFew, 611 RetsToMany, 612 NoReason 613 }; 614 615 struct { 616 Errors code = NotFound; 617 } reason; 618 603 619 Finder( CandidateFinder & f ) 604 : s elfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),620 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 605 621 targetType( f.targetType ) {} 606 622 607 623 void previsit( const ast::Node * ) { visit_children = false; } 608 624 … … 611 627 void addCandidate( Args &&... args ) { 612 628 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 629 reason.code = NoReason; 613 630 } 614 631 … … 639 656 640 657 /// Completes a function candidate with arguments located 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 658 void validateFunctionCandidate( 659 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 660 CandidateList & out 644 661 ) { 645 ast::ApplicationExpr * appExpr = 662 ast::ApplicationExpr * appExpr = 646 663 new ast::ApplicationExpr{ func->expr->location, func->expr }; 647 664 // sum cost and accumulate arguments … … 657 674 appExpr->args = move( vargs ); 658 675 // build and validate new candidate 659 auto newCand = 676 auto newCand = 660 677 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 661 678 PRINT( … … 669 686 /// Builds a list of candidates for a function, storing them in out 670 687 void makeFunctionCandidates( 671 const CandidateRef & func, const ast::FunctionType * funcType, 688 const CandidateRef & func, const ast::FunctionType * funcType, 672 689 const ExplodedArgs_new & args, CandidateList & out 673 690 ) { … … 676 693 ast::TypeEnvironment funcEnv{ func->env }; 677 694 makeUnifiableVars( funcType, funcOpen, funcNeed ); 678 // add all type variables as open variables now so that those not used in the parameter679 // list are still considered open695 // add all type variables as open variables now so that those not used in the 696 // parameter list are still considered open 680 697 funcEnv.add( funcType->forall ); 681 698 682 699 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) { 683 700 // attempt to narrow based on expected target type 684 const ast::Type * returnType = funcType->returns.front() ->get_type();685 if ( ! unify( 686 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 701 const ast::Type * returnType = funcType->returns.front(); 702 if ( ! unify( 703 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 687 704 ) { 688 705 // unification failed, do not pursue this candidate … … 696 713 std::size_t genStart = 0; 697 714 698 for ( const ast::DeclWithType * param : funcType->params ) { 699 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param ); 700 // Try adding the arguments corresponding to the current parameter to the existing 715 // xxx - how to handle default arg after change to ftype representation? 716 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) { 717 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) { 718 // function may have default args only if directly calling by name 719 // must use types on candidate however, due to RenameVars substitution 720 auto nParams = funcType->params.size(); 721 722 for (size_t i=0; i<nParams; ++i) { 723 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 724 if (!instantiateArgument( 725 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 726 } 727 goto endMatch; 728 } 729 } 730 for ( const auto & param : funcType->params ) { 731 // Try adding the arguments corresponding to the current parameter to the existing 701 732 // matches 702 if ( ! instantiateArgument( 703 obj->type, obj->init, args, results, genStart, symtab ) ) return; 704 } 705 733 // no default args for indirect calls 734 if ( ! instantiateArgument( 735 param, nullptr, args, results, genStart, symtab ) ) return; 736 } 737 738 endMatch: 706 739 if ( funcType->isVarArgs ) { 707 740 // append any unused arguments to vararg pack … … 750 783 if ( expl.exprs.empty() ) { 751 784 results.emplace_back( 752 results[i], move( env ), copy( results[i].need ), 753 copy( results[i].have ), move( open ), nextArg + 1, 785 results[i], move( env ), copy( results[i].need ), 786 copy( results[i].have ), move( open ), nextArg + 1, 754 787 expl.cost ); 755 788 … … 760 793 results.emplace_back( 761 794 i, expl.exprs.front(), move( env ), copy( results[i].need ), 762 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 795 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 763 796 expl.exprs.size() == 1 ? 0 : 1, j ); 764 797 } … … 780 813 /// Adds implicit struct-conversions to the alternative list 781 814 void addAnonConversions( const CandidateRef & cand ) { 782 // adds anonymous member interpretations whenever an aggregate value type is seen. 783 // it's okay for the aggregate expression to have reference type -- cast it to the 815 // adds anonymous member interpretations whenever an aggregate value type is seen. 816 // it's okay for the aggregate expression to have reference type -- cast it to the 784 817 // base type to treat the aggregate as the referenced value 785 818 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 786 819 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 787 820 cand->env.apply( aggrType ); 788 821 789 822 if ( aggrType.as< ast::ReferenceType >() ) { 790 823 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; … … 799 832 800 833 /// Adds aggregate member interpretations 801 void addAggMembers( 802 const ast:: ReferenceToType * aggrInst, const ast::Expr * expr,803 const Candidate & cand, const Cost & addedCost, const std::string & name 834 void addAggMembers( 835 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 836 const Candidate & cand, const Cost & addedCost, const std::string & name 804 837 ) { 805 838 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 806 839 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 807 CandidateRef newCand = std::make_shared<Candidate>( 840 CandidateRef newCand = std::make_shared<Candidate>( 808 841 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 809 // add anonymous member interpretations whenever an aggregate value type is seen 842 // add anonymous member interpretations whenever an aggregate value type is seen 810 843 // as a member expression 811 844 addAnonConversions( newCand ); … … 815 848 816 849 /// Adds tuple member interpretations 817 void addTupleMembers( 818 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 819 const Cost & addedCost, const ast::Expr * member 850 void addTupleMembers( 851 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 852 const Cost & addedCost, const ast::Expr * member 820 853 ) { 821 854 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 822 // get the value of the constant expression as an int, must be between 0 and the 855 // get the value of the constant expression as an int, must be between 0 and the 823 856 // length of the tuple to have meaning 824 857 long long val = constantExpr->intValue(); 825 858 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 826 859 addCandidate( 827 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 860 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 828 861 addedCost ); 829 862 } … … 832 865 833 866 void postvisit( const ast::UntypedExpr * untypedExpr ) { 834 CandidateFinder funcFinder{ symtab, tenv }; 835 funcFinder.find( untypedExpr->func, ResolvMode::withAdjustment() ); 836 // short-circuit if no candidates 837 if ( funcFinder.candidates.empty() ) return; 838 839 std::vector< CandidateFinder > argCandidates = 867 std::vector< CandidateFinder > argCandidates = 840 868 selfFinder.findSubExprs( untypedExpr->args ); 841 869 842 870 // take care of possible tuple assignments 843 871 // if not tuple assignment, handled as normal function call 844 872 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates ); 873 874 CandidateFinder funcFinder{ symtab, tenv }; 875 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) { 876 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 877 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) { 878 assertf(!argCandidates.empty(), "special function call without argument"); 879 for (auto & firstArgCand: argCandidates[0]) { 880 ast::ptr<ast::Type> argType = firstArgCand->expr->result; 881 firstArgCand->env.apply(argType); 882 // strip references 883 // xxx - is this correct? 884 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base; 885 886 // convert 1-tuple to plain type 887 if (auto tuple = argType.as<ast::TupleType>()) { 888 if (tuple->size() == 1) { 889 argType = tuple->types[0]; 890 } 891 } 892 893 // if argType is an unbound type parameter, all special functions need to be searched. 894 if (isUnboundType(argType)) { 895 funcFinder.otypeKeys.clear(); 896 break; 897 } 898 899 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer); 900 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type)); 901 } 902 } 903 } 904 // if candidates are already produced, do not fail 905 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates? 906 // this means there exists ctor/assign functions with a tuple as first parameter. 907 ResolvMode mode = { 908 true, // adjust 909 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name 910 selfFinder.candidates.empty() // failfast if other options are not found 911 }; 912 funcFinder.find( untypedExpr->func, mode ); 913 // short-circuit if no candidates 914 // if ( funcFinder.candidates.empty() ) return; 915 916 reason.code = NoMatch; 845 917 846 918 // find function operators … … 877 949 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 878 950 CandidateRef newFunc{ new Candidate{ *func } }; 879 newFunc->expr = 951 newFunc->expr = 880 952 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 881 953 makeFunctionCandidates( newFunc, function, argExpansions, found ); 882 954 } 883 } else if ( 884 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 955 } else if ( 956 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 885 957 ) { 886 if ( const ast::EqvClass * clz = func->env.lookup( inst->name) ) {958 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 887 959 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 888 960 CandidateRef newFunc{ new Candidate{ *func } }; 889 newFunc->expr = 961 newFunc->expr = 890 962 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 891 963 makeFunctionCandidates( newFunc, function, argExpansions, found ); … … 901 973 std::vector< ExplodedArg > funcE; 902 974 funcE.reserve( funcFinder.candidates.size() ); 903 for ( const CandidateRef & func : funcFinder ) { 975 for ( const CandidateRef & func : funcFinder ) { 904 976 funcE.emplace_back( *func, symtab ); 905 977 } … … 913 985 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 914 986 CandidateRef newOp{ new Candidate{ *op} }; 915 newOp->expr = 987 newOp->expr = 916 988 referenceToRvalueConversion( newOp->expr, newOp->cost ); 917 989 makeFunctionCandidates( newOp, function, argExpansions, found ); … … 922 994 } 923 995 924 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 996 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 925 997 // candidates 926 998 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } … … 934 1006 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 935 1007 auto function = pointer->base.strict_as< ast::FunctionType >(); 936 1008 937 1009 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 938 1010 std::cerr << "parameters are:" << std::endl; … … 957 1029 promoteCvtCost( winners ); 958 1030 959 // function may return a struct/union value, in which case we need to add candidates 960 // for implicit conversions to each of the anonymous members, which must happen after 1031 // function may return a struct/union value, in which case we need to add candidates 1032 // for implicit conversions to each of the anonymous members, which must happen after 961 1033 // `findMinCost`, since anon conversions are never the cheapest 962 1034 for ( const CandidateRef & c : winners ) { … … 966 1038 967 1039 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 968 // If resolution is unsuccessful with a target type, try again without, since it 1040 // If resolution is unsuccessful with a target type, try again without, since it 969 1041 // will sometimes succeed when it wouldn't with a target type binding. 970 1042 // For example: … … 983 1055 /// true if expression is an lvalue 984 1056 static bool isLvalue( const ast::Expr * x ) { 985 return x->result && ( x-> result->is_lvalue() || x->result.as< ast::ReferenceType >() );1057 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 986 1058 } 987 1059 … … 989 1061 CandidateFinder finder{ symtab, tenv }; 990 1062 finder.find( addressExpr->arg ); 1063 1064 if( finder.candidates.empty() ) return; 1065 1066 reason.code = NoMatch; 1067 991 1068 for ( CandidateRef & r : finder.candidates ) { 992 1069 if ( ! isLvalue( r->expr ) ) continue; … … 1003 1080 assert( toType ); 1004 1081 toType = resolveTypeof( toType, symtab ); 1005 toType = SymTab::validateType( castExpr->location, toType, symtab );1082 // toType = SymTab::validateType( castExpr->location, toType, symtab ); 1006 1083 toType = adjustExprType( toType, tenv, symtab ); 1007 1084 1008 1085 CandidateFinder finder{ symtab, tenv, toType }; 1009 1086 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1087 1088 if( !finder.candidates.empty() ) reason.code = NoMatch; 1010 1089 1011 1090 CandidateList matches; … … 1016 1095 cand->env.extractOpenVars( open ); 1017 1096 1018 // It is possible that a cast can throw away some values in a multiply-valued 1019 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1020 // subexpression results that are cast directly. The candidate is invalid if it 1097 // It is possible that a cast can throw away some values in a multiply-valued 1098 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1099 // subexpression results that are cast directly. The candidate is invalid if it 1021 1100 // has fewer results than there are types to cast to. 1022 1101 int discardedValues = cand->expr->result->size() - toType->size(); … … 1025 1104 // unification run for side-effects 1026 1105 unify( toType, cand->expr->result, cand->env, need, have, open, symtab ); 1027 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env ); 1106 Cost thisCost = 1107 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast) 1108 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ) 1109 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ); 1110 1028 1111 PRINT( 1029 1112 std::cerr << "working on cast with result: " << toType << std::endl; … … 1037 1120 // count one safe conversion for each value that is thrown away 1038 1121 thisCost.incSafe( discardedValues ); 1039 CandidateRef newCand = std::make_shared<Candidate>( 1040 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1041 copy( cand->env ), move( open ), move( need ), cand->cost, 1122 CandidateRef newCand = std::make_shared<Candidate>( 1123 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1124 copy( cand->env ), move( open ), move( need ), cand->cost, 1042 1125 cand->cost + thisCost ); 1043 1126 inferParameters( newCand, matches ); … … 1057 1140 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1058 1141 for ( CandidateRef & r : finder.candidates ) { 1059 addCandidate( 1060 *r, 1142 addCandidate( 1143 *r, 1061 1144 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1062 1145 } 1146 } 1147 1148 void postvisit( const ast::KeywordCastExpr * castExpr ) { 1149 const auto & loc = castExpr->location; 1150 assertf( castExpr->result, "Cast target should have been set in Validate." ); 1151 auto ref = castExpr->result.strict_as<ast::ReferenceType>(); 1152 auto inst = ref->base.strict_as<ast::StructInstType>(); 1153 auto target = inst->base.get(); 1154 1155 CandidateFinder finder{ symtab, tenv }; 1156 1157 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) { 1158 for(auto & cand : found) { 1159 const ast::Type * expr = cand->expr->result.get(); 1160 if(expect_ref) { 1161 auto res = dynamic_cast<const ast::ReferenceType*>(expr); 1162 if(!res) { continue; } 1163 expr = res->base.get(); 1164 } 1165 1166 if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) { 1167 auto td = cand->env.lookup(*insttype); 1168 if(!td) { continue; } 1169 expr = td->bound.get(); 1170 } 1171 1172 if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) { 1173 if(base->base == target) { 1174 candidates.push_back( std::move(cand) ); 1175 reason.code = NoReason; 1176 } 1177 } 1178 } 1179 }; 1180 1181 try { 1182 // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd 1183 // Clone is purely for memory management 1184 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) }; 1185 1186 // don't prune here, since it's guaranteed all alternatives will have the same type 1187 finder.find( tech1.get(), ResolvMode::withoutPrune() ); 1188 pick_alternatives(finder.candidates, false); 1189 1190 return; 1191 } catch(SemanticErrorException & ) {} 1192 1193 // Fallback : turn (thread&)X into ($thread&)get_thread(X) 1194 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) }; 1195 // don't prune here, since it's guaranteed all alternatives will have the same type 1196 finder.find( fallback.get(), ResolvMode::withoutPrune() ); 1197 1198 pick_alternatives(finder.candidates, true); 1199 1200 // Whatever happens here, we have no more fallbacks 1063 1201 } 1064 1202 … … 1067 1205 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1068 1206 for ( CandidateRef & agg : aggFinder.candidates ) { 1069 // it's okay for the aggregate expression to have reference type -- cast it to the 1207 // it's okay for the aggregate expression to have reference type -- cast it to the 1070 1208 // base type to treat the aggregate as the referenced value 1071 1209 Cost addedCost = Cost::zero; … … 1074 1212 // find member of the given type 1075 1213 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1076 addAggMembers( 1214 addAggMembers( 1077 1215 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1078 1216 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1079 addAggMembers( 1217 addAggMembers( 1080 1218 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1081 1219 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1090 1228 1091 1229 void postvisit( const ast::NameExpr * nameExpr ) { 1092 std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name ); 1230 std::vector< ast::SymbolTable::IdData > declList; 1231 if (!selfFinder.otypeKeys.empty()) { 1232 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 1233 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str()); 1234 1235 for (auto & otypeKey: selfFinder.otypeKeys) { 1236 auto result = symtab.specialLookupId(kind, otypeKey); 1237 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end())); 1238 } 1239 } 1240 else { 1241 declList = symtab.lookupId( nameExpr->name ); 1242 } 1093 1243 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1244 1245 if( declList.empty() ) return; 1246 1247 reason.code = NoMatch; 1248 1094 1249 for ( auto & data : declList ) { 1095 1250 Cost cost = Cost::zero; … … 1097 1252 1098 1253 CandidateRef newCand = std::make_shared<Candidate>( 1099 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1254 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1100 1255 cost ); 1101 1256 PRINT( … … 1107 1262 std::cerr << std::endl; 1108 1263 ) 1109 newCand->expr = ast::mutate_field( 1110 newCand->expr.get(), &ast::Expr::result, 1264 newCand->expr = ast::mutate_field( 1265 newCand->expr.get(), &ast::Expr::result, 1111 1266 renameTyVars( newCand->expr->result ) ); 1112 // add anonymous member interpretations whenever an aggregate value type is seen 1267 // add anonymous member interpretations whenever an aggregate value type is seen 1113 1268 // as a name expression 1114 1269 addAnonConversions( newCand ); … … 1120 1275 // not sufficient to just pass `variableExpr` here, type might have changed since 1121 1276 // creation 1122 addCandidate( 1277 addCandidate( 1123 1278 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1124 1279 } … … 1130 1285 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1131 1286 if ( sizeofExpr->type ) { 1132 addCandidate( 1133 new ast::SizeofExpr{ 1134 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1287 addCandidate( 1288 new ast::SizeofExpr{ 1289 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1135 1290 tenv ); 1136 1291 } else { … … 1141 1296 CandidateList winners = findMinCost( finder.candidates ); 1142 1297 if ( winners.size() != 1 ) { 1143 SemanticError( 1298 SemanticError( 1144 1299 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1145 1300 } … … 1154 1309 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1155 1310 if ( alignofExpr->type ) { 1156 addCandidate( 1157 new ast::AlignofExpr{ 1158 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1311 addCandidate( 1312 new ast::AlignofExpr{ 1313 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1159 1314 tenv ); 1160 1315 } else { … … 1165 1320 CandidateList winners = findMinCost( finder.candidates ); 1166 1321 if ( winners.size() != 1 ) { 1167 SemanticError( 1322 SemanticError( 1168 1323 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1169 1324 } … … 1172 1327 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1173 1328 choice->cost = Cost::zero; 1174 addCandidate( 1329 addCandidate( 1175 1330 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1176 1331 } … … 1178 1333 1179 1334 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) { 1180 const ast:: ReferenceToType * aggInst;1335 const ast::BaseInstType * aggInst; 1181 1336 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ; 1182 1337 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ; … … 1185 1340 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1186 1341 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1187 addCandidate( 1342 addCandidate( 1188 1343 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1189 1344 } … … 1206 1361 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1207 1362 if ( finder2.candidates.empty() ) return; 1363 1364 reason.code = NoMatch; 1208 1365 1209 1366 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1218 1375 1219 1376 addCandidate( 1220 new ast::LogicalExpr{ 1377 new ast::LogicalExpr{ 1221 1378 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1222 1379 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1240 1397 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1241 1398 if ( finder3.candidates.empty() ) return; 1399 1400 reason.code = NoMatch; 1242 1401 1243 1402 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1256 1415 ast::AssertionSet have; 1257 1416 1258 // unify true and false results, then infer parameters to produce new 1417 // unify true and false results, then infer parameters to produce new 1259 1418 // candidates 1260 1419 ast::ptr< ast::Type > common; 1261 if ( 1262 unify( 1263 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1264 common ) 1420 if ( 1421 unify( 1422 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1423 common ) 1265 1424 ) { 1266 1425 // generate typed expression 1267 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1426 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1268 1427 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1269 1428 newExpr->result = common ? common : r2->expr->result; 1270 1429 // convert both options to result type 1271 1430 Cost cost = r1->cost + r2->cost + r3->cost; 1272 newExpr->arg2 = computeExpressionConversionCost( 1431 newExpr->arg2 = computeExpressionConversionCost( 1273 1432 newExpr->arg2, newExpr->result, symtab, env, cost ); 1274 1433 newExpr->arg3 = computeExpressionConversionCost( … … 1287 1446 ast::TypeEnvironment env{ tenv }; 1288 1447 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1289 1448 1290 1449 CandidateFinder finder2{ symtab, env }; 1291 1450 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1317 1476 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1318 1477 if ( finder2.candidates.empty() ) return; 1478 1479 reason.code = NoMatch; 1319 1480 1320 1481 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1330 1491 1331 1492 ast::ptr< ast::Type > common; 1332 if ( 1333 unify( 1334 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1335 common ) 1493 if ( 1494 unify( 1495 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1496 common ) 1336 1497 ) { 1337 1498 // generate new expression 1338 ast::RangeExpr * newExpr = 1499 ast::RangeExpr * newExpr = 1339 1500 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1340 1501 newExpr->result = common ? common : r1->expr->result; 1341 1502 // add candidate 1342 1503 CandidateRef newCand = std::make_shared<Candidate>( 1343 newExpr, move( env ), move( open ), move( need ), 1504 newExpr, move( env ), move( open ), move( need ), 1344 1505 r1->cost + r2->cost ); 1345 1506 inferParameters( newCand, candidates ); … … 1350 1511 1351 1512 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1352 std::vector< CandidateFinder > subCandidates = 1513 std::vector< CandidateFinder > subCandidates = 1353 1514 selfFinder.findSubExprs( tupleExpr->exprs ); 1354 1515 std::vector< CandidateList > possibilities; … … 1370 1531 1371 1532 addCandidate( 1372 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1533 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1373 1534 move( env ), move( open ), move( need ), sumCost( subs ) ); 1374 1535 } … … 1410 1571 // calculate target type 1411 1572 const ast::Type * toType = resolveTypeof( initAlt.type, symtab ); 1412 toType = SymTab::validateType( initExpr->location, toType, symtab );1573 // toType = SymTab::validateType( initExpr->location, toType, symtab ); 1413 1574 toType = adjustExprType( toType, tenv, symtab ); 1414 // The call to find must occur inside this loop, otherwise polymorphic return 1415 // types are not bound to the initialization type, since return type variables are 1416 // only open for the duration of resolving the UntypedExpr. 1575 // The call to find must occur inside this loop, otherwise polymorphic return 1576 // types are not bound to the initialization type, since return type variables are 1577 // only open for the duration of resolving the UntypedExpr. 1417 1578 CandidateFinder finder{ symtab, tenv, toType }; 1418 1579 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1419 1580 for ( CandidateRef & cand : finder.candidates ) { 1581 if(reason.code == NotFound) reason.code = NoMatch; 1582 1420 1583 ast::TypeEnvironment env{ cand->env }; 1421 1584 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; … … 1426 1589 ) 1427 1590 1428 // It is possible that a cast can throw away some values in a multiply-valued 1429 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1430 // the subexpression results that are cast directly. The candidate is invalid 1591 // It is possible that a cast can throw away some values in a multiply-valued 1592 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1593 // the subexpression results that are cast directly. The candidate is invalid 1431 1594 // if it has fewer results than there are types to cast to. 1432 1595 int discardedValues = cand->expr->result->size() - toType->size(); … … 1434 1597 1435 1598 // unification run for side-effects 1436 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1437 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1438 1599 bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab ); 1600 (void) canUnify; 1601 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1602 symtab, env ); 1603 PRINT( 1604 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1605 symtab, env ); 1606 std::cerr << "Considering initialization:"; 1607 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl; 1608 std::cerr << std::endl << " TO: " << toType << std::endl; 1609 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed"); 1610 std::cerr << std::endl << " Legacy cost " << legacyCost; 1611 std::cerr << std::endl << " New cost " << thisCost; 1612 std::cerr << std::endl; 1613 ) 1439 1614 if ( thisCost != Cost::infinity ) { 1440 1615 // count one safe conversion for each value that is thrown away 1441 1616 thisCost.incSafe( discardedValues ); 1442 CandidateRef newCand = std::make_shared<Candidate>( 1443 new ast::InitExpr{ 1444 initExpr->location, restructureCast( cand->expr, toType ), 1445 initAlt.designation }, 1446 copy( cand->env), move( open ), move( need ), cand->cost, thisCost );1617 CandidateRef newCand = std::make_shared<Candidate>( 1618 new ast::InitExpr{ 1619 initExpr->location, restructureCast( cand->expr, toType ), 1620 initAlt.designation }, 1621 move(env), move( open ), move( need ), cand->cost, thisCost ); 1447 1622 inferParameters( newCand, matches ); 1448 1623 } 1449 1624 } 1625 1450 1626 } 1451 1627 … … 1469 1645 }; 1470 1646 1471 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1647 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder"); 1648 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1472 1649 /// return type. Skips ambiguous candidates. 1473 CandidateList pruneCandidates( CandidateList & candidates ) { 1474 struct PruneStruct { 1475 CandidateRef candidate; 1476 bool ambiguous; 1477 1478 PruneStruct() = default; 1479 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1480 }; 1481 1482 // find lowest-cost candidate for each type 1483 std::unordered_map< std::string, PruneStruct > selected; 1484 for ( CandidateRef & candidate : candidates ) { 1485 std::string mangleName; 1650 1651 } // anonymous namespace 1652 1653 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) { 1654 struct PruneStruct { 1655 CandidateRef candidate; 1656 bool ambiguous; 1657 1658 PruneStruct() = default; 1659 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1660 }; 1661 1662 // find lowest-cost candidate for each type 1663 std::unordered_map< std::string, PruneStruct > selected; 1664 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found 1665 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;}); 1666 for ( CandidateRef & candidate : candidates ) { 1667 std::string mangleName; 1668 { 1669 ast::ptr< ast::Type > newType = candidate->expr->result; 1670 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1671 candidate->env.apply( newType ); 1672 mangleName = Mangle::mangle( newType ); 1673 } 1674 1675 auto found = selected.find( mangleName ); 1676 if (found != selected.end() && found->second.candidate->cost < candidate->cost) { 1677 PRINT( 1678 std::cerr << "cost " << candidate->cost << " loses to " 1679 << found->second.candidate->cost << std::endl; 1680 ) 1681 continue; 1682 } 1683 1684 // xxx - when do satisfyAssertions produce more than 1 result? 1685 // this should only happen when initial result type contains 1686 // unbound type parameters, then it should never be pruned by 1687 // the previous step, since renameTyVars guarantees the mangled name 1688 // is unique. 1689 CandidateList satisfied; 1690 bool needRecomputeKey = false; 1691 if (candidate->need.empty()) { 1692 satisfied.emplace_back(candidate); 1693 } 1694 else { 1695 satisfyAssertions(candidate, localSyms, satisfied, errors); 1696 needRecomputeKey = true; 1697 } 1698 1699 for (auto & newCand : satisfied) { 1700 // recomputes type key, if satisfyAssertions changed it 1701 if (needRecomputeKey) 1486 1702 { 1487 ast::ptr< ast::Type > newType = candidate->expr->result; 1488 candidate->env.apply( newType ); 1703 ast::ptr< ast::Type > newType = newCand->expr->result; 1704 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get()); 1705 newCand->env.apply( newType ); 1489 1706 mangleName = Mangle::mangle( newType ); 1490 1707 } 1491 1492 1708 auto found = selected.find( mangleName ); 1493 1709 if ( found != selected.end() ) { 1494 if ( candidate->cost < found->second.candidate->cost ) {1710 if ( newCand->cost < found->second.candidate->cost ) { 1495 1711 PRINT( 1496 std::cerr << "cost " << candidate->cost << " beats "1712 std::cerr << "cost " << newCand->cost << " beats " 1497 1713 << found->second.candidate->cost << std::endl; 1498 1714 ) 1499 1715 1500 found->second = PruneStruct{ candidate};1501 } else if ( candidate->cost == found->second.candidate->cost ) {1502 // if one of the candidates contains a deleted identifier, can pick the other, 1503 // since deleted expressions should not be ambiguous if there is another option 1716 found->second = PruneStruct{ newCand }; 1717 } else if ( newCand->cost == found->second.candidate->cost ) { 1718 // if one of the candidates contains a deleted identifier, can pick the other, 1719 // since deleted expressions should not be ambiguous if there is another option 1504 1720 // that is at least as good 1505 if ( findDeletedExpr( candidate->expr ) ) {1721 if ( findDeletedExpr( newCand->expr ) ) { 1506 1722 // do nothing 1507 1723 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 1508 1724 } else if ( findDeletedExpr( found->second.candidate->expr ) ) { 1509 1725 PRINT( std::cerr << "current is deleted" << std::endl; ) 1510 found->second = PruneStruct{ candidate};1726 found->second = PruneStruct{ newCand }; 1511 1727 } else { 1512 1728 PRINT( std::cerr << "marking ambiguous" << std::endl; ) 1513 1729 found->second.ambiguous = true; 1514 1730 } 1515 } else { 1731 } else { 1732 // xxx - can satisfyAssertions increase the cost? 1516 1733 PRINT( 1517 std::cerr << "cost " << candidate->cost << " loses to "1734 std::cerr << "cost " << newCand->cost << " loses to " 1518 1735 << found->second.candidate->cost << std::endl; 1519 ) 1736 ) 1520 1737 } 1521 1738 } else { 1522 selected.emplace_hint( found, mangleName, candidate ); 1523 } 1524 } 1525 1526 // report unambiguous min-cost candidates 1527 CandidateList out; 1528 for ( auto & target : selected ) { 1529 if ( target.second.ambiguous ) continue; 1530 1531 CandidateRef cand = target.second.candidate; 1532 1533 ast::ptr< ast::Type > newResult = cand->expr->result; 1534 cand->env.applyFree( newResult ); 1535 cand->expr = ast::mutate_field( 1536 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1537 1538 out.emplace_back( cand ); 1539 } 1540 return out; 1739 selected.emplace_hint( found, mangleName, newCand ); 1740 } 1741 } 1541 1742 } 1542 1743 1543 } // anonymous namespace 1744 // report unambiguous min-cost candidates 1745 // CandidateList out; 1746 for ( auto & target : selected ) { 1747 if ( target.second.ambiguous ) continue; 1748 1749 CandidateRef cand = target.second.candidate; 1750 1751 ast::ptr< ast::Type > newResult = cand->expr->result; 1752 cand->env.applyFree( newResult ); 1753 cand->expr = ast::mutate_field( 1754 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1755 1756 out.emplace_back( cand ); 1757 } 1758 // if everything is lost in satisfyAssertions, report the error 1759 return !selected.empty(); 1760 } 1544 1761 1545 1762 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) { … … 1549 1766 1550 1767 if ( mode.failFast && candidates.empty() ) { 1551 SemanticError( expr, "No reasonable alternatives for expression " ); 1768 switch(finder.core.reason.code) { 1769 case Finder::NotFound: 1770 { SemanticError( expr, "No alternatives for expression " ); break; } 1771 case Finder::NoMatch: 1772 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1773 case Finder::ArgsToFew: 1774 case Finder::ArgsToMany: 1775 case Finder::RetsToFew: 1776 case Finder::RetsToMany: 1777 case Finder::NoReason: 1778 default: 1779 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1780 } 1552 1781 } 1553 1782 1783 /* 1554 1784 if ( mode.satisfyAssns || mode.prune ) { 1555 1785 // trim candidates to just those where the assertions are satisfiable … … 1558 1788 std::vector< std::string > errors; 1559 1789 for ( CandidateRef & candidate : candidates ) { 1560 satisfyAssertions( candidate, symtab, satisfied, errors );1790 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1561 1791 } 1562 1792 … … 1574 1804 candidates = move( satisfied ); 1575 1805 } 1806 */ 1576 1807 1577 1808 if ( mode.prune ) { … … 1582 1813 ) 1583 1814 1584 CandidateList pruned = pruneCandidates( candidates ); 1585 1815 CandidateList pruned; 1816 std::vector<std::string> errors; 1817 bool found = pruneCandidates( candidates, pruned, errors ); 1818 1586 1819 if ( mode.failFast && pruned.empty() ) { 1587 1820 std::ostringstream stream; 1588 CandidateList winners = findMinCost( candidates ); 1589 stream << "Cannot choose between " << winners.size() << " alternatives for " 1590 "expression\n"; 1591 ast::print( stream, expr ); 1592 stream << " Alternatives are:\n"; 1593 print( stream, winners, 1 ); 1594 SemanticError( expr->location, stream.str() ); 1821 if (found) { 1822 CandidateList winners = findMinCost( candidates ); 1823 stream << "Cannot choose between " << winners.size() << " alternatives for " 1824 "expression\n"; 1825 ast::print( stream, expr ); 1826 stream << " Alternatives are:\n"; 1827 print( stream, winners, 1 ); 1828 SemanticError( expr->location, stream.str() ); 1829 } 1830 else { 1831 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1832 for ( const auto& err : errors ) { 1833 stream << err; 1834 } 1835 SemanticError( expr->location, stream.str() ); 1836 } 1595 1837 } 1596 1838 … … 1602 1844 ) 1603 1845 PRINT( 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1846 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1605 1847 << std::endl; 1606 1848 ) 1607 1849 } 1608 1850 1609 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1851 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1610 1852 // adjusted 1611 1853 if ( mode.adjust ) { 1612 1854 for ( CandidateRef & r : candidates ) { 1613 r->expr = ast::mutate_field( 1614 r->expr.get(), &ast::Expr::result, 1615 adjustExprType( r->expr->result, r->env, symtab) );1855 r->expr = ast::mutate_field( 1856 r->expr.get(), &ast::Expr::result, 1857 adjustExprType( r->expr->result, r->env, localSyms ) ); 1616 1858 } 1617 1859 } … … 1625 1867 } 1626 1868 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1869 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1870 const std::vector< ast::ptr< ast::Expr > > & xs 1629 1871 ) { 1630 1872 std::vector< CandidateFinder > out; 1631 1873 1632 1874 for ( const auto & x : xs ) { 1633 out.emplace_back( symtab, env );1875 out.emplace_back( localSyms, env ); 1634 1876 out.back().find( x, ResolvMode::withAdjustment() ); 1635 1877 1636 1878 PRINT( 1637 1879 std::cerr << "findSubExprs" << std::endl; -
src/ResolvExpr/CandidateFinder.hpp
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 9:51:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 28 28 struct CandidateFinder { 29 29 CandidateList candidates; ///< List of candidate resolutions 30 const ast::SymbolTable & symtab; ///< Symbol table to lookup candidates30 const ast::SymbolTable & localSyms; ///< Symbol table to lookup candidates 31 31 const ast::TypeEnvironment & env; ///< Substitutions performed in this resolution 32 32 ast::ptr< ast::Type > targetType; ///< Target type for resolution 33 std::set< std::string > otypeKeys; /// different type may map to same key 33 34 34 CandidateFinder( 35 const ast::SymbolTable & sym tab, const ast::TypeEnvironment & env,35 CandidateFinder( 36 const ast::SymbolTable & syms, const ast::TypeEnvironment & env, 36 37 const ast::Type * tt = nullptr ) 37 : candidates(), symtab( symtab), env( env ), targetType( tt ) {}38 : candidates(), localSyms( syms ), env( env ), targetType( tt ) {} 38 39 39 40 /// Fill candidates with feasible resolutions for `expr` 40 41 void find( const ast::Expr * expr, ResolvMode mode = {} ); 42 bool pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ); 41 43 42 44 /// Runs new candidate finder on each element in xs, returning the list of finders … … 49 51 iterator begin() { return candidates.begin(); } 50 52 const_iterator begin() const { return candidates.begin(); } 51 53 52 54 iterator end() { return candidates.end(); } 53 55 const_iterator end() const { return candidates.end(); } … … 55 57 56 58 /// Computes conversion cost between two types 57 Cost computeConversionCost( 58 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,59 const ast:: TypeEnvironment & env );59 Cost computeConversionCost( 60 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 61 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 60 62 61 63 } // namespace ResolvExpr -
src/ResolvExpr/CastCost.cc
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 06:57:43 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:12:00 201913 // Update Count : 812 // Last Modified On : Tue Oct 4 15:00:00 2019 13 // Update Count : 9 14 14 // 15 15 … … 142 142 143 143 CastCost_new( 144 const ast::Type * dst, const ast::SymbolTable & symtab,144 const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 145 145 const ast::TypeEnvironment & env, CostCalculation costFunc ) 146 : ConversionCost_new( dst, s ymtab, env, costFunc ) {}146 : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {} 147 147 148 148 void postvisit( const ast::BasicType * basicType ) { … … 152 152 cost = Cost::unsafe; 153 153 } else { 154 cost = conversionCost( basicType, dst, s ymtab, env );154 cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env ); 155 155 } 156 156 } … … 165 165 } else { 166 166 ast::TypeEnvironment newEnv{ env }; 167 if ( auto wParams = pointerType->base.as< ast:: ParameterizedType >() ) {167 if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) { 168 168 newEnv.add( wParams->forall ); 169 169 } … … 183 183 } 184 184 }; 185 186 #warning For overload resolution between the two versions. 187 int localPtrsCastable(const ast::Type * t1, const ast::Type * t2, 188 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) { 189 return ptrsCastable( t1, t2, symtab, env ); 190 } 191 Cost localCastCost( 192 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 193 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 194 ) { return castCost( src, dst, srcIsLvalue, symtab, env ); } 185 195 } // anonymous namespace 186 196 197 198 187 199 Cost castCost( 188 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,189 const ast:: TypeEnvironment & env200 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 201 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 190 202 ) { 191 203 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 192 if ( const ast::EqvClass * eqvClass = env.lookup( typeInst->name) ) {204 if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) { 193 205 // check cast cost against bound type, if present 194 206 if ( eqvClass->bound ) { 195 return castCost( src, eqvClass->bound, s ymtab, env );207 return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env ); 196 208 } else { 197 209 return Cost::infinity; … … 201 213 auto type = strict_dynamic_cast< const ast::TypeDecl * >( named ); 202 214 if ( type->base ) { 203 return castCost( src, type->base, s ymtab, env ) + Cost::safe;215 return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe; 204 216 } 205 217 } … … 224 236 #warning cast on ptrsCastable artifact of having two functions, remove when port done 225 237 return convertToReferenceCost( 226 src, refType, symtab, env, 227 ( int (*)( 228 const ast::Type *, const ast::Type *, const ast::SymbolTable &, 229 const ast::TypeEnvironment & ) 230 ) ptrsCastable ); 238 src, refType, srcIsLvalue, symtab, env, localPtrsCastable ); 231 239 } else { 232 240 #warning cast on castCost artifact of having two functions, remove when port done 233 ast::Pass< CastCost_new > converter{ 234 dst, symtab, env, 235 ( Cost (*)( 236 const ast::Type *, const ast::Type *, const ast::SymbolTable &, 237 const ast::TypeEnvironment & ) 238 ) castCost }; 241 ast::Pass< CastCost_new > converter( 242 dst, srcIsLvalue, symtab, env, localCastCost ); 239 243 src->accept( converter ); 240 return converter. pass.cost;244 return converter.core.cost; 241 245 } 242 246 } -
src/ResolvExpr/CommonType.cc
rbdfc032 reef8dfb 666 666 const ast::OpenVarSet & open; 667 667 public: 668 static size_t traceId; 668 669 ast::ptr< ast::Type > result; 669 670 … … 712 713 const ast::Type * base = oPtr->base; 713 714 if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) { 714 auto entry = open.find( var->name);715 auto entry = open.find( *var ); 715 716 if ( entry != open.end() ) { 716 717 ast::AssertionSet need, have; … … 893 894 }; 894 895 896 // size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new"); 895 897 namespace { 896 898 ast::ptr< ast::Type > handleReference( … … 939 941 ast::ptr< ast::Type > result; 940 942 const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >(); 941 const ast::ReferenceType * ref2 = type 1.as< ast::ReferenceType >();943 const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >(); 942 944 943 945 if ( depth1 > depth2 ) { … … 966 968 ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open }; 967 969 type1->accept( visitor ); 968 ast::ptr< ast::Type > result = visitor. pass.result;970 ast::ptr< ast::Type > result = visitor.core.result; 969 971 970 972 // handling for opaque type declarations (?) -
src/ResolvExpr/ConversionCost.cc
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 07:06:19 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Aug 12 10:21:00 201913 // Update Count : 2 712 // Last Modified On : Wed Jul 29 16:11:00 2020 13 // Update Count : 28 14 14 // 15 15 … … 392 392 void ConversionCost::postvisit( const FunctionType * ) {} 393 393 394 void ConversionCost::postvisit( const StructInstType * inst ) {395 if ( const StructInstType * destAsInst = dynamic_cast< const StructInstType * >( dest ) ) {396 if ( inst->name == destAsInst->name ) {397 cost = Cost::zero;398 } // if399 } // if400 }401 402 void ConversionCost::postvisit( const UnionInstType * inst ) {403 if ( const UnionInstType * destAsInst = dynamic_cast< const UnionInstType * >( dest ) ) {404 if ( inst->name == destAsInst->name ) {405 cost = Cost::zero;406 } // if407 } // if408 }409 410 394 void ConversionCost::postvisit( const EnumInstType * ) { 411 395 static Type::Qualifiers q; … … 497 481 } 498 482 499 static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 500 const ast::SymbolTable &, const ast::TypeEnvironment & env ) {501 return ptrsAssignable( t1, t2, env );502 } 503 504 // TODO: This is used for overload resolution. It might be able to be dropped once the old system 505 // is removed. 506 static Cost localConversionCost( 507 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,508 const ast::TypeEnvironment & env509 ) { return conversionCost( src, dst, symtab, env );}483 namespace { 484 # warning For overload resolution between the two versions. 485 int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 486 const ast::SymbolTable &, const ast::TypeEnvironment & env ) { 487 return ptrsAssignable( t1, t2, env ); 488 } 489 Cost localConversionCost( 490 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 491 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 492 ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); } 493 } 510 494 511 495 Cost conversionCost( 512 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,513 const ast:: TypeEnvironment & env496 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 497 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 514 498 ) { 515 499 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 516 if ( const ast::EqvClass * eqv = env.lookup( inst->name) ) {500 if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) { 517 501 if ( eqv->bound ) { 518 return conversionCost(src, eqv->bound, s ymtab, env );502 return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env ); 519 503 } else { 520 504 return Cost::infinity; … … 524 508 assertf( type, "Unexpected typedef." ); 525 509 if ( type->base ) { 526 return conversionCost( src, type->base, s ymtab, env ) + Cost::safe;510 return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe; 527 511 } 528 512 } … … 534 518 } else if ( const ast::ReferenceType * refType = 535 519 dynamic_cast< const ast::ReferenceType * >( dst ) ) { 536 return convertToReferenceCost( src, refType, s ymtab, env, localPtrsAssignable );520 return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable ); 537 521 } else { 538 ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost ); 539 src->accept( converter ); 540 return converter.pass.cost; 541 } 542 } 543 544 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, 522 return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost ); 523 } 524 } 525 526 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 545 527 int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 546 NumCostCalculation func ) {528 PtrsCalculation func ) { 547 529 if ( 0 < diff ) { 548 530 Cost cost = convertToReferenceCost( 549 strict_dynamic_cast< const ast::ReferenceType * >( src )->base, 550 dst, (diff - 1), symtab, env, func );531 strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst, 532 srcIsLvalue, (diff - 1), symtab, env, func ); 551 533 cost.incReference(); 552 534 return cost; … … 554 536 Cost cost = convertToReferenceCost( 555 537 src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base, 556 (diff + 1), symtab, env, func );538 srcIsLvalue, (diff + 1), symtab, env, func ); 557 539 cost.incReference(); 558 540 return cost; … … 579 561 } 580 562 } else { 581 ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost ); 582 src->accept( converter ); 583 return converter.pass.cost; 563 return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost ); 584 564 } 585 565 } else { … … 588 568 assert( dstAsRef ); 589 569 if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) { 590 if ( src ->is_lvalue()) {570 if ( srcIsLvalue ) { 591 571 if ( src->qualifiers == dstAsRef->base->qualifiers ) { 592 572 return Cost::reference; … … 607 587 608 588 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst, 609 610 NumCostCalculation func ) {589 bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 590 PtrsCalculation func ) { 611 591 int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth(); 612 return convertToReferenceCost( src, dst, s depth - ddepth, symtab, env, func );592 return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func ); 613 593 } 614 594 … … 667 647 assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) ); 668 648 669 cost = costCalc( refType->base, dst, s ymtab, env );649 cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env ); 670 650 if ( refType->base->qualifiers == dst->qualifiers ) { 671 651 cost.incReference(); … … 681 661 } 682 662 683 void ConversionCost_new::postvisit( const ast::StructInstType * structInstType ) {684 if ( const ast::StructInstType * dstAsInst =685 dynamic_cast< const ast::StructInstType * >( dst ) ) {686 if ( structInstType->name == dstAsInst->name ) {687 cost = Cost::zero;688 }689 }690 }691 692 void ConversionCost_new::postvisit( const ast::UnionInstType * unionInstType ) {693 if ( const ast::UnionInstType * dstAsInst =694 dynamic_cast< const ast::UnionInstType * >( dst ) ) {695 if ( unionInstType->name == dstAsInst->name ) {696 cost = Cost::zero;697 }698 }699 }700 701 663 void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) { 702 664 (void)enumInstType; 703 static const ast::BasicType integer( ast::BasicType::SignedInt );704 cost = costCalc( &integer, dst, symtab, env );665 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) }; 666 cost = costCalc( integer, dst, srcIsLvalue, symtab, env ); 705 667 if ( cost < Cost::unsafe ) { 706 668 cost.incSafe(); … … 713 675 714 676 void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) { 715 if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {716 cost = costCalc( eqv->bound, dst, s ymtab, env );677 if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) { 678 cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env ); 717 679 } else if ( const ast::TypeInstType * dstAsInst = 718 680 dynamic_cast< const ast::TypeInstType * >( dst ) ) { 719 if ( typeInstType->name == dstAsInst->name) {681 if ( *typeInstType == *dstAsInst ) { 720 682 cost = Cost::zero; 721 683 } … … 724 686 assertf( type, "Unexpected typedef."); 725 687 if ( type->base ) { 726 cost = costCalc( type->base, dst, s ymtab, env ) + Cost::safe;688 cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe; 727 689 } 728 690 } … … 737 699 auto dstEnd = dstAsTuple->types.end(); 738 700 while ( srcIt != srcEnd && dstIt != dstEnd ) { 739 Cost newCost = costCalc( * srcIt++, * dstIt++, s ymtab, env );701 Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env ); 740 702 if ( newCost == Cost::infinity ) { 741 703 return; … … 772 734 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 773 735 } 736 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 737 cost = Cost::zero; 738 // +1 for zero_t ->, +1 for disambiguation 739 cost.incSafe( maxIntCost + 2 ); 774 740 } 775 741 } … … 789 755 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 790 756 } 791 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 792 cost = Cost::zero; 793 cost.incSafe( maxIntCost + 2 ); 794 } 795 } 796 757 } 758 } 759 // size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost"); 797 760 798 761 } // namespace ResolvExpr -
src/ResolvExpr/ConversionCost.h
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 09:37:28 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Aug 8 16:13:00 201913 // Update Count : 612 // Last Modified On : Wed Jul 29 16:12:00 2020 13 // Update Count : 7 14 14 // 15 15 … … 51 51 void postvisit( const ReferenceType * refType ); 52 52 void postvisit( const FunctionType * functionType ); 53 void postvisit( const StructInstType * aggregateUseType );54 void postvisit( const UnionInstType * aggregateUseType );55 53 void postvisit( const EnumInstType * aggregateUseType ); 56 54 void postvisit( const TraitInstType * aggregateUseType ); … … 74 72 75 73 // Some function pointer types, differ in return type. 76 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, 74 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool, 77 75 const ast::SymbolTable &, const ast::TypeEnvironment &)>; 78 using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,76 using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *, 79 77 const ast::SymbolTable &, const ast::TypeEnvironment &)>; 80 78 … … 83 81 protected: 84 82 const ast::Type * dst; 83 bool srcIsLvalue; 85 84 const ast::SymbolTable & symtab; 86 85 const ast::TypeEnvironment & env; 87 86 CostCalculation costCalc; 88 87 public: 88 static size_t traceId; 89 89 Cost cost; 90 Cost result() { return cost; } 90 91 91 ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,92 ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 92 93 const ast::TypeEnvironment & env, CostCalculation costCalc ) : 93 dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity ) 94 dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ), 95 costCalc( costCalc ), cost( Cost::infinity ) 94 96 {} 95 97 … … 102 104 void postvisit( const ast::ReferenceType * refType ); 103 105 void postvisit( const ast::FunctionType * functionType ); 104 void postvisit( const ast::StructInstType * structInstType );105 void postvisit( const ast::UnionInstType * unionInstType );106 106 void postvisit( const ast::EnumInstType * enumInstType ); 107 107 void postvisit( const ast::TraitInstType * traitInstType ); … … 114 114 115 115 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest, 116 const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func ); 116 bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, 117 PtrsCalculation func ); 117 118 118 119 } // namespace ResolvExpr -
src/ResolvExpr/CurrentObject.cc
rbdfc032 reef8dfb 21 21 #include <string> // for string, operator<<, allocator 22 22 23 #include "AST/Copy.hpp" // for shallowCopy 23 24 #include "AST/Expr.hpp" // for InitAlternative 24 25 #include "AST/GenericSubstitution.hpp" // for genericSubstitution 25 26 #include "AST/Init.hpp" // for Designation 26 27 #include "AST/Node.hpp" // for readonly 28 #include "AST/Print.hpp" // for readonly 27 29 #include "AST/Type.hpp" 28 30 #include "Common/Indenter.h" // for Indenter, operator<< … … 592 594 class SimpleIterator final : public MemberIterator { 593 595 CodeLocation location; 594 readonly< Type >type = nullptr;596 const Type * type = nullptr; 595 597 public: 596 598 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {} 597 599 598 void setPosition( 599 std::deque< ptr< Expr > >::const_iterator begin, 600 void setPosition( 601 std::deque< ptr< Expr > >::const_iterator begin, 600 602 std::deque< ptr< Expr > >::const_iterator end 601 603 ) override { … … 628 630 class ArrayIterator final : public MemberIterator { 629 631 CodeLocation location; 630 readonly< ArrayType >array = nullptr;631 readonly< Type >base = nullptr;632 const ArrayType * array = nullptr; 633 const Type * base = nullptr; 632 634 size_t index = 0; 633 635 size_t size = 0; … … 637 639 auto res = eval(expr); 638 640 if ( ! res.second ) { 639 SemanticError( location, 641 SemanticError( location, 640 642 toString("Array designator must be a constant expression: ", expr ) ); 641 643 } … … 644 646 645 647 public: 646 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 648 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 647 649 : location( loc ), array( at ), base( at->base ) { 648 650 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) … … 655 657 656 658 void setPosition( const Expr * expr ) { 657 // need to permit integer-constant-expressions, including: integer constants, 658 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 // need to permit integer-constant-expressions, including: integer constants, 660 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 661 // cast expressions 660 662 if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 662 664 index = constExpr->intValue(); 663 665 } catch ( SemanticErrorException & ) { 664 SemanticError( expr, 666 SemanticError( expr, 665 667 "Constant expression of non-integral type in array designator: " ); 666 668 } 667 669 } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) { 668 670 setPosition( castExpr->arg ); 669 } else if ( 670 dynamic_cast< const SizeofExpr * >( expr ) 671 || dynamic_cast< const AlignofExpr * >( expr ) 671 } else if ( 672 dynamic_cast< const SizeofExpr * >( expr ) 673 || dynamic_cast< const AlignofExpr * >( expr ) 672 674 ) { 673 675 index = 0; 674 676 } else { 675 assertf( false, 677 assertf( false, 676 678 "bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 677 679 } 678 680 } 679 681 680 void setPosition( 681 std::deque< ptr< Expr > >::const_iterator begin, 682 void setPosition( 683 std::deque< ptr< Expr > >::const_iterator begin, 682 684 std::deque< ptr< Expr > >::const_iterator end 683 685 ) override { … … 758 760 } 759 761 760 AggregateIterator( 761 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 AggregateIterator( 763 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 764 const MemberList & ms ) 763 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 765 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 764 766 sub( genericSubstitution( i ) ) { 765 767 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) … … 768 770 769 771 public: 770 void setPosition( 771 std::deque< ptr< Expr > >::const_iterator begin, 772 void setPosition( 773 std::deque< ptr< Expr > >::const_iterator begin, 772 774 std::deque< ptr< Expr > >::const_iterator end 773 775 ) final { … … 786 788 return; 787 789 } 788 assertf( false, 790 assertf( false, 789 791 "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 790 792 } else { 791 assertf( false, 793 assertf( false, 792 794 "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() ); 793 795 } … … 803 805 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 804 806 // need to substitute for generic types so that casts are to concrete types 807 alt.type = shallowCopy(alt.type.get()); 805 808 PRINT( std::cerr << " type is: " << alt.type; ) 806 809 sub.apply( alt.type ); // also apply to designation?? … … 842 845 for ( InitAlternative & alt : ret ) { 843 846 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 844 alt.designation.get_and_mutate()->designators.emplace_front( 847 alt.designation.get_and_mutate()->designators.emplace_front( 845 848 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 846 849 } … … 897 900 class TupleIterator final : public AggregateIterator { 898 901 public: 899 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 900 : AggregateIterator( 901 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 903 : AggregateIterator( 904 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 905 ) {} 903 906 … … 920 923 921 924 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) { 922 if ( auto aggr = dynamic_cast< const ReferenceToType * >( type ) ) {925 if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) { 923 926 if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) { 924 927 return new StructIterator{ loc, sit }; … … 926 929 return new UnionIterator{ loc, uit }; 927 930 } else { 928 assertf( 929 dynamic_cast< const EnumInstType * >( aggr )930 || dynamic_cast< const TypeInstType * >( aggr ),931 "Encountered unhandled ReferenceToType in createMemberIterator: %s",931 assertf( 932 dynamic_cast< const EnumInstType * >( type ) 933 || dynamic_cast< const TypeInstType * >( type ), 934 "Encountered unhandled BaseInstType in createMemberIterator: %s", 932 935 toString( type ).c_str() ); 933 936 return new SimpleIterator{ loc, type }; … … 949 952 using DesignatorChain = std::deque< ptr< Expr > >; 950 953 PRINT( std::cerr << "___findNext" << std::endl; ) 951 954 952 955 // find all the d's 953 956 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts; … … 962 965 DesignatorChain & d = *dit; 963 966 PRINT( std::cerr << "____actual: " << t << std::endl; ) 964 if ( auto refType = dynamic_cast< const ReferenceToType * >( t ) ) {967 if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) { 965 968 // concatenate identical field names 966 969 for ( const Decl * mem : refType->lookup( nexpr->name ) ) { … … 1013 1016 // set new designators 1014 1017 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 1015 Designation * actualDesignation = 1018 Designation * actualDesignation = 1016 1019 new Designation{ designation->location, DesignatorChain{d} }; 1017 1020 objStack.back()->setPosition( d ); // destroys d -
src/ResolvExpr/FindOpenVars.cc
rbdfc032 reef8dfb 112 112 // mark open/closed variables 113 113 if ( nextIsOpen ) { 114 for ( const ast::TypeDecl *decl : type->forall ) {115 open[ decl->name ] = ast::TypeDecl::Data{ decl};116 for ( const ast::DeclWithType * assert : decl->assertions ) {117 need[ assert ].isUsed = false;118 }114 for ( auto & decl : type->forall ) { 115 open[ *decl ] = ast::TypeDecl::Data{ decl->base }; 116 } 117 for ( auto & assert : type->assertions ) { 118 need[ assert ].isUsed = false; 119 119 } 120 120 } else { 121 for ( const ast::TypeDecl *decl : type->forall ) {122 closed[ decl->name ] = ast::TypeDecl::Data{ decl };123 for ( const ast::DeclWithType * assert : decl->assertions ) {124 have[ assert ].isUsed = false;125 }121 for ( auto & decl : type->forall ) { 122 closed[ *decl ] = ast::TypeDecl::Data{ decl->base }; 123 } 124 for ( auto & assert : type->assertions ) { 125 have[ assert ].isUsed = false; 126 126 } 127 127 } -
src/ResolvExpr/PolyCost.cc
rbdfc032 reef8dfb 58 58 59 59 // TODO: When the old PolyCost is torn out get rid of the _new suffix. 60 struct PolyCost_new { 60 class PolyCost_new { 61 const ast::SymbolTable &symtab; 62 public: 61 63 int result; 62 const ast::SymbolTable &symtab;63 64 const ast::TypeEnvironment &env_; 64 65 65 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :66 result( 0 ), symtab( symtab), env_( env ) {}66 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 67 : symtab( symtab ), result( 0 ), env_( env ) {} 67 68 68 69 void previsit( const ast::TypeInstType * type ) { 69 if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {70 if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) { 70 71 if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) { 71 72 if ( symtab.lookupType( otherType->name ) ) { … … 86 87 ast::Pass<PolyCost_new> costing( symtab, env ); 87 88 type->accept( costing ); 88 return costing. pass.result;89 return costing.core.result; 89 90 } 90 91 -
src/ResolvExpr/PtrsAssignable.cc
rbdfc032 reef8dfb 134 134 } 135 135 void postvisit( const ast::TypeInstType * inst ) { 136 if ( const ast::EqvClass * eqv = typeEnv.lookup( inst->name) ) {136 if ( const ast::EqvClass * eqv = typeEnv.lookup( *inst ) ) { 137 137 if ( eqv->bound ) { 138 138 // T * = S * for any S depends on the type bound to T … … 146 146 const ast::TypeEnvironment & env ) { 147 147 if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 148 if ( const ast::EqvClass * eqv = env.lookup( dstAsInst->name) ) {148 if ( const ast::EqvClass * eqv = env.lookup( *dstAsInst ) ) { 149 149 return ptrsAssignable( src, eqv->bound, env ); 150 150 } … … 155 155 ast::Pass<PtrsAssignable_new> visitor( dst, env ); 156 156 src->accept( visitor ); 157 return visitor. pass.result;157 return visitor.core.result; 158 158 } 159 159 -
src/ResolvExpr/PtrsCastable.cc
rbdfc032 reef8dfb 180 180 } 181 181 } 182 } else if ( const ast::EqvClass * eqvClass = env.lookup( inst->name) ) {182 } else if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) { 183 183 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) { 184 184 return -1; … … 283 283 ) { 284 284 if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 285 if ( const ast::EqvClass * eqvClass = env.lookup( inst->name) ) {285 if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) { 286 286 return ptrsAssignable( src, eqvClass->bound, env ); 287 287 } … … 293 293 ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab }; 294 294 src->accept( ptrs ); 295 return ptrs. pass.result;295 return ptrs.core.result; 296 296 } 297 297 } -
src/ResolvExpr/RenameVars.cc
rbdfc032 reef8dfb 30 30 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 31 31 32 #include "AST/Copy.hpp" 33 32 34 namespace ResolvExpr { 33 35 … … 36 38 int level = 0; 37 39 int resetCount = 0; 40 41 int next_expr_id = 1; 42 int next_usage_id = 1; 38 43 ScopedMap< std::string, std::string > nameMap; 39 44 ScopedMap< std::string, ast::TypeInstType::TypeEnvKey > idMap; 40 45 public: 41 46 void reset() { … … 44 49 } 45 50 46 using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;47 48 51 void rename( TypeInstType * type ) { 49 mapConstIteratorit = nameMap.find( type->name );52 auto it = nameMap.find( type->name ); 50 53 if ( it != nameMap.end() ) { 51 54 type->name = it->second; 52 55 } 56 } 57 58 void nextUsage() { 59 ++next_usage_id; 53 60 } 54 61 … … 65 72 // ditto for assertion names, the next level in 66 73 level++; 67 // acceptAll( td->assertions, *this ); 68 } // for 69 } // if 74 } 75 } 70 76 } 71 77 … … 77 83 78 84 const ast::TypeInstType * rename( const ast::TypeInstType * type ) { 79 mapConstIterator it = nameMap.find( type->name ); 80 if ( it != nameMap.end() ) { 81 ast::TypeInstType * mutType = ast::mutate( type ); 82 mutType->name = it->second; 83 type = mutType; 84 } 85 // rename 86 auto it = idMap.find( type->name ); 87 if ( it != idMap.end() ) { 88 // unconditionally mutate because map will *always* have different name 89 ast::TypeInstType * mut = ast::shallowCopy( type ); 90 // reconcile base node since some copies might have been made 91 mut->base = it->second.base; 92 mut->formal_usage = it->second.formal_usage; 93 mut->expr_id = it->second.expr_id; 94 type = mut; 95 } 96 85 97 return type; 86 98 } 87 99 88 template<typename NodeT> 89 const NodeT * openLevel( const NodeT * type ) { 90 if ( !type->forall.empty() ) { 91 nameMap.beginScope(); 92 // Load new names from this forall clause and perform renaming. 93 NodeT * mutType = ast::mutate( type ); 94 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 95 std::ostringstream output; 96 output << "_" << resetCount << "_" << level << "_" << td->name; 97 std::string newname( output.str() ); 98 nameMap[ td->name ] = newname; 99 ++level; 100 101 ast::TypeDecl * decl = ast::mutate( td.get() ); 102 decl->name = newname; 103 td = decl; 104 } 105 } 106 return type; 107 } 108 109 template<typename NodeT> 110 const NodeT * closeLevel( const NodeT * type ) { 111 if ( !type->forall.empty() ) { 112 nameMap.endScope(); 113 } 114 return type; 100 const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) { 101 if ( type->forall.empty() ) return type; 102 idMap.beginScope(); 103 104 // Load new names from this forall clause and perform renaming. 105 auto mutType = ast::shallowCopy( type ); 106 // assert( type == mutType && "mutated type must be unique from ForallSubstitutor" ); 107 for ( auto & td : mutType->forall ) { 108 auto mut = ast::shallowCopy( td.get() ); 109 // assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" ); 110 111 if (mode == GEN_EXPR_ID) { 112 mut->expr_id = next_expr_id; 113 mut->formal_usage = -1; 114 ++next_expr_id; 115 } 116 else if (mode == GEN_USAGE) { 117 assertf(mut->expr_id, "unfilled expression id in generating candidate type"); 118 mut->formal_usage = next_usage_id; 119 } 120 else { 121 assert(false); 122 } 123 idMap[ td->name ] = ast::TypeInstType::TypeEnvKey(*mut); 124 125 td = mut; 126 } 127 128 return mutType; 129 } 130 131 void closeLevel( const ast::FunctionType * type ) { 132 if ( type->forall.empty() ) return; 133 idMap.endScope(); 115 134 } 116 135 }; … … 119 138 RenamingData renaming; 120 139 121 struct RenameVars {140 struct RenameVars_old { 122 141 void previsit( TypeInstType * instType ) { 123 142 renaming.openLevel( (Type*)instType ); … … 130 149 renaming.closeLevel( type ); 131 150 } 151 }; 152 153 struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ { 154 RenameMode mode; 132 155 133 156 const ast::FunctionType * previsit( const ast::FunctionType * type ) { 134 return renaming.openLevel( type ); 135 } 157 return renaming.openLevel( type, mode ); 158 } 159 160 /* 136 161 const ast::StructInstType * previsit( const ast::StructInstType * type ) { 137 162 return renaming.openLevel( type ); … … 143 168 return renaming.openLevel( type ); 144 169 } 170 */ 171 145 172 const ast::TypeInstType * previsit( const ast::TypeInstType * type ) { 146 return renaming.rename( renaming.openLevel( type ) ); 147 } 148 const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) { 149 return renaming.closeLevel( type ); 173 if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type 174 return renaming.rename( type ); 175 } 176 void postvisit( const ast::FunctionType * type ) { 177 renaming.closeLevel( type ); 150 178 } 151 179 }; … … 154 182 155 183 void renameTyVars( Type * t ) { 156 PassVisitor<RenameVars > renamer;184 PassVisitor<RenameVars_old> renamer; 157 185 t->accept( renamer ); 158 186 } 159 187 160 const ast::Type * renameTyVars( const ast::Type * t ) { 161 ast::Pass<RenameVars> renamer; 188 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) { 189 // ast::Type *tc = ast::deepCopy(t); 190 ast::Pass<RenameVars_new> renamer; 191 renamer.core.mode = mode; 192 if (mode == GEN_USAGE && reset) { 193 renaming.nextUsage(); 194 } 162 195 return t->accept( renamer ); 163 196 } … … 165 198 void resetTyVarRenaming() { 166 199 renaming.reset(); 200 renaming.nextUsage(); 167 201 } 168 202 -
src/ResolvExpr/RenameVars.h
rbdfc032 reef8dfb 30 30 /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID 31 31 void renameTyVars( Type * ); 32 const ast::Type * renameTyVars( const ast::Type * ); 32 33 enum RenameMode { 34 GEN_USAGE, // for type in VariableExpr 35 GEN_EXPR_ID // for type in decl 36 }; 37 const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true ); 38 33 39 34 40 /// resets internal state of renamer to avoid overflow 35 41 void resetTyVarRenaming(); 42 43 36 44 } // namespace ResolvExpr 37 45 -
src/ResolvExpr/ResolvMode.h
rbdfc032 reef8dfb 22 22 const bool prune; ///< Prune alternatives to min-cost per return type? [true] 23 23 const bool failFast; ///< Fail on no resulting alternatives? [true] 24 const bool satisfyAssns; ///< Satisfy assertions? [false]25 24 26 private: 27 constexpr ResolvMode(bool a, bool p, bool ff, bool sa) 28 : adjust(a), prune(p), failFast(ff), satisfyAssns(sa) {} 25 constexpr ResolvMode(bool a, bool p, bool ff) 26 : adjust(a), prune(p), failFast(ff) {} 29 27 30 public:31 28 /// Default settings 32 constexpr ResolvMode() : adjust(false), prune(true), failFast(true) , satisfyAssns(false){}29 constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {} 33 30 34 31 /// With adjust flag set; turns array and function types into equivalent pointers 35 static constexpr ResolvMode withAdjustment() { return { true, true, true , false}; }32 static constexpr ResolvMode withAdjustment() { return { true, true, true }; } 36 33 37 34 /// With adjust flag set but prune unset; pruning ensures there is at least one alternative 38 35 /// per result type 39 static constexpr ResolvMode withoutPrune() { return { true, false, true , false}; }36 static constexpr ResolvMode withoutPrune() { return { true, false, true }; } 40 37 41 38 /// With adjust and prune flags set but failFast unset; failFast ensures there is at least 42 39 /// one resulting alternative 43 static constexpr ResolvMode withoutFailFast() { return { true, true, false , false}; }40 static constexpr ResolvMode withoutFailFast() { return { true, true, false }; } 44 41 45 42 /// The same mode, but with satisfyAssns turned on; for top-level calls 46 ResolvMode atTopLevel() const { return { adjust, prune, failFast, true}; }43 ResolvMode atTopLevel() const { return { adjust, true, failFast }; } 47 44 }; 48 45 } // namespace ResolvExpr -
src/ResolvExpr/ResolveAssertions.cc
rbdfc032 reef8dfb 277 277 const DeclarationWithType * candidate = cdata.id; 278 278 279 // build independent unification context for candidate 279 // ignore deleted candidates. 280 // NOTE: this behavior is different from main resolver. 281 // further investigations might be needed to determine 282 // if we should implement the same rule here 283 // (i.e. error if unique best match is deleted) 284 if (candidate->isDeleted) continue; 285 286 // build independent unification context. for candidate 280 287 AssertionSet have, newNeed; 281 288 TypeEnvironment newEnv{ resn.alt.env }; -
src/ResolvExpr/ResolveTypeof.cc
rbdfc032 reef8dfb 15 15 16 16 #include "ResolveTypeof.h" 17 #include "RenameVars.h" 17 18 18 19 #include <cassert> // for assert … … 29 30 #include "SynTree/Mutator.h" // for Mutator 30 31 #include "SynTree/Type.h" // for TypeofType, Type 32 #include "SymTab/Mangler.h" 33 #include "InitTweak/InitTweak.h" // for isConstExpr 31 34 32 35 namespace SymTab { … … 99 102 // replace basetypeof(<enum>) by int 100 103 if ( dynamic_cast<EnumInstType*>(newType) ) { 101 Type* newerType = 102 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 104 Type* newerType = 105 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 103 106 newType->attributes }; 104 107 delete newType; 105 108 newType = newerType; 106 109 } 107 newType->get_qualifiers().val 110 newType->get_qualifiers().val 108 111 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals; 109 112 } else { 110 113 newType->get_qualifiers().val |= oldQuals; 111 114 } 112 115 113 116 return newType; 114 117 } … … 120 123 ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {} 121 124 122 void pre mutate( const ast::TypeofType * ) { visit_children = false; }123 124 const ast::Type * post mutate( const ast::TypeofType * typeofType ) {125 void previsit( const ast::TypeofType * ) { visit_children = false; } 126 127 const ast::Type * postvisit( const ast::TypeofType * typeofType ) { 125 128 // pass on null expression 126 129 if ( ! typeofType->expr ) return typeofType; … … 133 136 // typeof wrapping expression 134 137 ast::TypeEnvironment dummy; 135 ast::ptr< ast::Expr > newExpr = 138 ast::ptr< ast::Expr > newExpr = 136 139 resolveInVoidContext( typeofType->expr, localSymtab, dummy ); 137 140 assert( newExpr->result && ! newExpr->result->isVoid() ); … … 143 146 // replace basetypeof(<enum>) by int 144 147 if ( newType.as< ast::EnumInstType >() ) { 145 newType = new ast::BasicType{ 148 newType = new ast::BasicType{ 146 149 ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) }; 147 150 } 148 reset_qualifiers( 149 newType, 151 reset_qualifiers( 152 newType, 150 153 ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers ); 151 154 } else { … … 153 156 } 154 157 155 return newType ;158 return newType.release(); 156 159 } 157 160 }; … … 161 164 ast::Pass< ResolveTypeof_new > mutator{ symtab }; 162 165 return type->accept( mutator ); 166 } 167 168 struct FixArrayDimension { 169 // should not require a mutable symbol table - prevent pass template instantiation 170 const ast::SymbolTable & _symtab; 171 FixArrayDimension(const ast::SymbolTable & symtab): _symtab(symtab) {} 172 173 const ast::ArrayType * previsit (const ast::ArrayType * arrayType) { 174 if (!arrayType->dimension) return arrayType; 175 auto mutType = mutate(arrayType); 176 ast::ptr<ast::Type> sizetype = ast::sizeType ? ast::sizeType : new ast::BasicType(ast::BasicType::LongUnsignedInt); 177 mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, _symtab); 178 179 if (InitTweak::isConstExpr(mutType->dimension)) { 180 mutType->isVarLen = ast::LengthFlag::FixedLen; 181 } 182 else { 183 mutType->isVarLen = ast::LengthFlag::VariableLen; 184 } 185 return mutType; 186 } 187 }; 188 189 const ast::Type * fixArrayType( const ast::Type * type, const ast::SymbolTable & symtab) { 190 ast::Pass<FixArrayDimension> visitor {symtab}; 191 return type->accept(visitor); 192 } 193 194 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab ) { 195 if (!decl->isTypeFixed) { 196 auto mutDecl = mutate(decl); 197 auto resolvedType = resolveTypeof(decl->type, symtab); 198 resolvedType = fixArrayType(resolvedType, symtab); 199 mutDecl->type = resolvedType; 200 201 // check variable length if object is an array. 202 // xxx - should this be part of fixObjectType? 203 204 /* 205 if (auto arrayType = dynamic_cast<const ast::ArrayType *>(resolvedType)) { 206 auto dimExpr = findSingleExpression(arrayType->dimension, ast::sizeType, symtab); 207 if (auto varexpr = arrayType->dimension.as<ast::VariableExpr>()) {// hoisted previously 208 if (InitTweak::isConstExpr(varexpr->var.strict_as<ast::ObjectDecl>()->init)) { 209 auto mutType = mutate(arrayType); 210 mutType->isVarLen = ast::LengthFlag::VariableLen; 211 mutDecl->type = mutType; 212 } 213 } 214 } 215 */ 216 217 218 if (!mutDecl->name.empty()) 219 mutDecl->mangleName = Mangle::mangle(mutDecl); // do not mangle unnamed variables 220 221 mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID); 222 mutDecl->isTypeFixed = true; 223 return mutDecl; 224 } 225 return decl; 163 226 } 164 227 -
src/ResolvExpr/ResolveTypeof.h
rbdfc032 reef8dfb 23 23 class Type; 24 24 class SymbolTable; 25 class ObjectDecl; 25 26 } 26 27 … … 28 29 Type *resolveTypeof( Type*, const SymTab::Indexer &indexer ); 29 30 const ast::Type * resolveTypeof( const ast::Type *, const ast::SymbolTable & ); 31 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab ); 30 32 } // namespace ResolvExpr 31 33 -
src/ResolvExpr/Resolver.cc
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Sun May 17 12:17:01 2015 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed May 29 11:00:00 201913 // Update Count : 24 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Mar 27 11:58:00 2020 13 // Update Count : 242 14 14 // 15 15 … … 26 26 #include "RenameVars.h" // for RenameVars, global_renamer 27 27 #include "Resolver.h" 28 #include "ResolveTypeof.h" 28 29 #include "ResolvMode.h" // for ResolvMode 29 30 #include "typeops.h" // for extractResultType 30 31 #include "Unify.h" // for unify 32 #include "CompilationState.h" 31 33 #include "AST/Chain.hpp" 32 34 #include "AST/Decl.hpp" … … 38 40 #include "Common/PassVisitor.h" // for PassVisitor 39 41 #include "Common/SemanticError.h" // for SemanticError 42 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 40 43 #include "Common/utility.h" // for ValueGuard, group_iterate 41 44 #include "InitTweak/GenInit.h" … … 44 47 #include "SymTab/Autogen.h" // for SizeType 45 48 #include "SymTab/Indexer.h" // for Indexer 49 #include "SymTab/Mangler.h" // for Mangler 46 50 #include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar... 47 51 #include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr … … 84 88 void previsit( ThrowStmt * throwStmt ); 85 89 void previsit( CatchStmt * catchStmt ); 90 void postvisit( CatchStmt * catchStmt ); 86 91 void previsit( WaitForStmt * stmt ); 87 92 … … 559 564 // TODO: Replace *exception type with &exception type. 560 565 if ( throwStmt->get_expr() ) { 561 const StructDecl * exception_decl = indexer.lookupStruct( "__cfa abi_ehm__base_exception_t" );566 const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" ); 562 567 assert( exception_decl ); 563 568 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) ); … … 567 572 568 573 void Resolver_old::previsit( CatchStmt * catchStmt ) { 574 // Until we are very sure this invarent (ifs that move between passes have thenPart) 575 // holds, check it. This allows a check for when to decode the mangling. 576 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) { 577 assert( ifStmt->thenPart ); 578 } 579 // Encode the catchStmt so the condition can see the declaration. 569 580 if ( catchStmt->cond ) { 570 findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer ); 581 IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body ); 582 catchStmt->cond = nullptr; 583 catchStmt->body = ifStmt; 584 } 585 } 586 587 void Resolver_old::postvisit( CatchStmt * catchStmt ) { 588 // Decode the catchStmt so everything is stored properly. 589 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ); 590 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) { 591 assert( ifStmt->condition ); 592 assert( ifStmt->elsePart ); 593 catchStmt->cond = ifStmt->condition; 594 catchStmt->body = ifStmt->elsePart; 595 ifStmt->condition = nullptr; 596 ifStmt->elsePart = nullptr; 597 delete ifStmt; 571 598 } 572 599 } … … 941 968 namespace { 942 969 /// Finds deleted expressions in an expression tree 943 struct DeleteFinder_new final : public ast::WithShortCircuiting {944 const ast::DeletedExpr * delExpr= nullptr;970 struct DeleteFinder_new final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder_new> { 971 const ast::DeletedExpr * result = nullptr; 945 972 946 973 void previsit( const ast::DeletedExpr * expr ) { 947 if ( delExpr ) { visit_children = false; } 948 else { delExpr = expr; } 949 } 950 951 void previsit( const ast::Expr * ) { 952 if ( delExpr ) { visit_children = false; } 974 if ( result ) { visit_children = false; } 975 else { result = expr; } 976 } 977 978 void previsit( const ast::Expr * expr ) { 979 if ( result ) { visit_children = false; } 980 if (expr->inferred.hasParams()) { 981 for (auto & imp : expr->inferred.inferParams() ) { 982 imp.second.expr->accept(*visitor); 983 } 984 } 953 985 } 954 986 }; 955 987 } // anonymous namespace 956 957 988 /// Check if this expression is or includes a deleted expression 958 989 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) { 959 ast::Pass<DeleteFinder_new> finder; 960 expr->accept( finder ); 961 return finder.pass.delExpr; 990 return ast::Pass<DeleteFinder_new>::read( expr ); 962 991 } 963 992 … … 1049 1078 /// Strips extraneous casts out of an expression 1050 1079 struct StripCasts_new final { 1051 const ast::Expr * post mutate( const ast::CastExpr * castExpr ) {1080 const ast::Expr * postvisit( const ast::CastExpr * castExpr ) { 1052 1081 if ( 1053 castExpr->isGenerated 1082 castExpr->isGenerated == ast::GeneratedCast 1054 1083 && typesCompatible( castExpr->arg->result, castExpr->result ) 1055 1084 ) { … … 1083 1112 } 1084 1113 1085 /// Establish post-resolver invariants for expressions 1114 1115 } // anonymous namespace 1116 /// Establish post-resolver invariants for expressions 1086 1117 void finishExpr( 1087 1118 ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env, … … 1096 1127 StripCasts_new::strip( expr ); 1097 1128 } 1098 } // anonymous namespace1099 1100 1129 1101 1130 ast::ptr< ast::Expr > resolveInVoidContext( … … 1105 1134 1106 1135 // set up and resolve expression cast to void 1107 ast:: CastExpr *untyped = new ast::CastExpr{ expr };1136 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr }; 1108 1137 CandidateRef choice = findUnfinishedKindExpression( 1109 1138 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() ); … … 1117 1146 } 1118 1147 1119 namespace { 1120 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1148 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1121 1149 /// context. 1122 1150 ast::ptr< ast::Expr > findVoidExpression( 1123 1151 const ast::Expr * untyped, const ast::SymbolTable & symtab 1124 1152 ) { 1125 resetTyVarRenaming();1126 1153 ast::TypeEnvironment env; 1127 1154 ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env ); … … 1129 1156 return newExpr; 1130 1157 } 1158 1159 namespace { 1160 1131 1161 1132 1162 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the … … 1140 1170 CandidateRef choice = 1141 1171 findUnfinishedKindExpression( untyped, symtab, kind, pred, mode ); 1142 finishExpr( choice->expr, choice->env, untyped->env );1172 ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env ); 1143 1173 return std::move( choice->expr ); 1144 1174 } … … 1148 1178 const ast::Expr * untyped, const ast::SymbolTable & symtab 1149 1179 ) { 1150 return findKindExpression( untyped, symtab ); 1180 Stats::ResolveTime::start( untyped ); 1181 auto res = findKindExpression( untyped, symtab ); 1182 Stats::ResolveTime::stop(); 1183 return res; 1151 1184 } 1152 1185 } // anonymous namespace 1153 1186 1154 1155 1156 1157 1158 1159 1160 1161 1162 1187 ast::ptr< ast::Expr > findSingleExpression( 1188 const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab 1189 ) { 1190 assert( untyped && type ); 1191 ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type }; 1192 ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab ); 1193 removeExtraneousCast( newExpr, symtab ); 1194 return newExpr; 1195 } 1163 1196 1164 1197 namespace { 1198 bool structOrUnion( const Candidate & i ) { 1199 const ast::Type * t = i.expr->result->stripReferences(); 1200 return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t ); 1201 } 1165 1202 /// Predicate for "Candidate has integral type" 1166 1203 bool hasIntegralType( const Candidate & i ) { … … 1198 1235 template<typename Iter> 1199 1236 inline bool nextMutex( Iter & it, const Iter & end ) { 1200 while ( it != end && ! (*it)-> get_type()->is_mutex() ) { ++it; }1237 while ( it != end && ! (*it)->is_mutex() ) { ++it; } 1201 1238 return it != end; 1202 1239 } … … 1210 1247 ast::ptr< ast::Type > functionReturn = nullptr; 1211 1248 ast::CurrentObject currentObject; 1249 // for work previously in GenInit 1250 static InitTweak::ManagedTypes_new managedTypes; 1251 1212 1252 bool inEnumDecl = false; 1213 1253 1214 1254 public: 1255 static size_t traceId; 1215 1256 Resolver_new() = default; 1216 1257 Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; } 1217 1258 1218 voidprevisit( const ast::FunctionDecl * );1259 const ast::FunctionDecl * previsit( const ast::FunctionDecl * ); 1219 1260 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * ); 1220 void previsit( const ast::ObjectDecl * ); 1261 const ast::ObjectDecl * previsit( const ast::ObjectDecl * ); 1262 void previsit( const ast::AggregateDecl * ); 1263 void previsit( const ast::StructDecl * ); 1221 1264 void previsit( const ast::EnumDecl * ); 1222 1265 const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * ); … … 1237 1280 const ast::ThrowStmt * previsit( const ast::ThrowStmt * ); 1238 1281 const ast::CatchStmt * previsit( const ast::CatchStmt * ); 1282 const ast::CatchStmt * postvisit( const ast::CatchStmt * ); 1239 1283 const ast::WaitForStmt * previsit( const ast::WaitForStmt * ); 1284 const ast::WithStmt * previsit( const ast::WithStmt * ); 1240 1285 1241 1286 const ast::SingleInit * previsit( const ast::SingleInit * ); 1242 1287 const ast::ListInit * previsit( const ast::ListInit * ); 1243 1288 const ast::ConstructorInit * previsit( const ast::ConstructorInit * ); 1289 1290 void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd); 1291 1292 void beginScope() { managedTypes.beginScope(); } 1293 void endScope() { managedTypes.endScope(); } 1294 bool on_error(ast::ptr<ast::Decl> & decl); 1244 1295 }; 1245 1246 void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) { 1247 ast::Pass< Resolver_new > resolver; 1248 accept_all( translationUnit, resolver ); 1296 // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver"); 1297 1298 InitTweak::ManagedTypes_new Resolver_new::managedTypes; 1299 1300 void resolve( ast::TranslationUnit& translationUnit ) { 1301 ast::Pass< Resolver_new >::run( translationUnit ); 1249 1302 } 1250 1303 … … 1257 1310 } 1258 1311 1259 ast::ptr< ast::Expr >resolveStmtExpr(1312 const ast::Expr * resolveStmtExpr( 1260 1313 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab 1261 1314 ) { 1262 1315 assert( stmtExpr ); 1263 1316 ast::Pass< Resolver_new > resolver{ symtab }; 1264 ast::ptr< ast::Expr > ret = stmtExpr; 1265 ret = ret->accept( resolver ); 1266 strict_dynamic_cast< ast::StmtExpr * >( ret.get_and_mutate() )->computeResult(); 1317 auto ret = mutate(stmtExpr->accept(resolver)); 1318 strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult(); 1267 1319 return ret; 1268 1320 } 1269 1321 1270 void Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) { 1322 namespace { 1323 const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ast::SymbolTable & symtab) { 1324 std::string name = attr->normalizedName(); 1325 if (name == "constructor" || name == "destructor") { 1326 if (attr->params.size() == 1) { 1327 auto arg = attr->params.front(); 1328 auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), symtab ); 1329 auto result = eval(arg); 1330 1331 auto mutAttr = mutate(attr); 1332 mutAttr->params.front() = resolved; 1333 if (! result.second) { 1334 SemanticWarning(loc, Warning::GccAttributes, 1335 toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) ); 1336 } 1337 else { 1338 auto priority = result.first; 1339 if (priority < 101) { 1340 SemanticWarning(loc, Warning::GccAttributes, 1341 toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) ); 1342 } else if (priority < 201 && ! buildingLibrary()) { 1343 SemanticWarning(loc, Warning::GccAttributes, 1344 toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) ); 1345 } 1346 } 1347 return mutAttr; 1348 } else if (attr->params.size() > 1) { 1349 SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) ); 1350 } else { 1351 SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) ); 1352 } 1353 } 1354 return attr; 1355 } 1356 } 1357 1358 const ast::FunctionDecl * Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) { 1271 1359 GuardValue( functionReturn ); 1360 1361 assert (functionDecl->unique()); 1362 if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) { 1363 SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations"); 1364 } 1365 1366 if (!functionDecl->isTypeFixed) { 1367 auto mutDecl = mutate(functionDecl); 1368 auto mutType = mutDecl->type.get_and_mutate(); 1369 1370 for (auto & attr: mutDecl->attributes) { 1371 attr = handleAttribute(mutDecl->location, attr, symtab); 1372 } 1373 1374 // handle assertions 1375 1376 symtab.enterScope(); 1377 mutType->forall.clear(); 1378 mutType->assertions.clear(); 1379 for (auto & typeParam : mutDecl->type_params) { 1380 symtab.addType(typeParam); 1381 mutType->forall.emplace_back(new ast::TypeInstType(typeParam->name, typeParam)); 1382 } 1383 for (auto & asst : mutDecl->assertions) { 1384 asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab); 1385 symtab.addId(asst); 1386 mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst)); 1387 } 1388 1389 // temporarily adds params to symbol table. 1390 // actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl) 1391 1392 std::vector<ast::ptr<ast::Type>> paramTypes; 1393 std::vector<ast::ptr<ast::Type>> returnTypes; 1394 1395 for (auto & param : mutDecl->params) { 1396 param = fixObjectType(param.strict_as<ast::ObjectDecl>(), symtab); 1397 symtab.addId(param); 1398 paramTypes.emplace_back(param->get_type()); 1399 } 1400 for (auto & ret : mutDecl->returns) { 1401 ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), symtab); 1402 returnTypes.emplace_back(ret->get_type()); 1403 } 1404 // since function type in decl is just a view of param types, need to update that as well 1405 mutType->params = std::move(paramTypes); 1406 mutType->returns = std::move(returnTypes); 1407 1408 auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID)); 1409 1410 std::list<ast::ptr<ast::Stmt>> newStmts; 1411 resolveWithExprs (mutDecl->withExprs, newStmts); 1412 1413 if (mutDecl->stmts) { 1414 auto mutStmt = mutDecl->stmts.get_and_mutate(); 1415 mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts)); 1416 mutDecl->stmts = mutStmt; 1417 } 1418 1419 symtab.leaveScope(); 1420 1421 mutDecl->type = renamedType; 1422 mutDecl->mangleName = Mangle::mangle(mutDecl); 1423 mutDecl->isTypeFixed = true; 1424 functionDecl = mutDecl; 1425 } 1426 managedTypes.handleDWT(functionDecl); 1427 1272 1428 functionReturn = extractResultType( functionDecl->type ); 1429 return functionDecl; 1273 1430 } 1274 1431 … … 1276 1433 // default value expressions have an environment which shouldn't be there and trips up 1277 1434 // later passes. 1278 as t::ptr< ast::FunctionDecl > ret = functionDecl;1279 for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {1280 const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i]; 1281 1282 if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {1435 assert( functionDecl->unique() ); 1436 ast::FunctionType * mutType = mutate( functionDecl->type.get() ); 1437 1438 for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) { 1439 if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) { 1283 1440 if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) { 1284 1441 if ( init->value->env == nullptr ) continue; 1285 1442 // clone initializer minus the initializer environment 1286 ast::chain_mutate( ret ) 1287 ( &ast::FunctionDecl::type ) 1288 ( &ast::FunctionType::params )[i] 1289 ( &ast::ObjectDecl::init ) 1290 ( &ast::SingleInit::value )->env = nullptr; 1291 1292 assert( functionDecl != ret.get() || functionDecl->unique() ); 1293 assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env ); 1443 auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() ); 1444 auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() ); 1445 auto mutValue = mutate( mutInit->value.get() ); 1446 1447 mutValue->env = nullptr; 1448 mutInit->value = mutValue; 1449 mutParam->init = mutInit; 1450 mutType->params[i] = mutParam; 1451 1452 assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env); 1294 1453 } 1295 1454 } 1296 1455 } 1297 return ret.get(); 1298 } 1299 1300 void Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) { 1456 mutate_field(functionDecl, &ast::FunctionDecl::type, mutType); 1457 return functionDecl; 1458 } 1459 1460 const ast::ObjectDecl * Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) { 1301 1461 // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()], 1302 1462 // class-variable `initContext` is changed multiple times because the LHS is analyzed … … 1306 1466 // selecting the RHS. 1307 1467 GuardValue( currentObject ); 1308 currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() }; 1468 1309 1469 if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) { 1310 1470 // enumerator initializers should not use the enum type to initialize, since the 1311 1471 // enum type is still incomplete at this point. Use `int` instead. 1472 objectDecl = fixObjectType(objectDecl, symtab); 1312 1473 currentObject = ast::CurrentObject{ 1313 1474 objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } }; 1314 1475 } 1476 else { 1477 if (!objectDecl->isTypeFixed) { 1478 auto newDecl = fixObjectType(objectDecl, symtab); 1479 auto mutDecl = mutate(newDecl); 1480 1481 // generate CtorInit wrapper when necessary. 1482 // in certain cases, fixObjectType is called before reaching 1483 // this object in visitor pass, thus disabling CtorInit codegen. 1484 // this happens on aggregate members and function parameters. 1485 if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) { 1486 // constructed objects cannot be designated 1487 if ( InitTweak::isDesignated( mutDecl->init ) ) SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" ); 1488 // constructed objects should not have initializers nested too deeply 1489 if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " ); 1490 1491 mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl ); 1492 } 1493 1494 objectDecl = mutDecl; 1495 } 1496 currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() }; 1497 } 1498 1499 return objectDecl; 1500 } 1501 1502 void Resolver_new::previsit( const ast::AggregateDecl * _aggDecl ) { 1503 auto aggDecl = mutate(_aggDecl); 1504 assertf(aggDecl == _aggDecl, "type declarations must be unique"); 1505 1506 for (auto & member: aggDecl->members) { 1507 // nested type decls are hoisted already. no need to do anything 1508 if (auto obj = member.as<ast::ObjectDecl>()) { 1509 member = fixObjectType(obj, symtab); 1510 } 1511 } 1512 } 1513 1514 void Resolver_new::previsit( const ast::StructDecl * structDecl ) { 1515 previsit(static_cast<const ast::AggregateDecl *>(structDecl)); 1516 managedTypes.handleStruct(structDecl); 1315 1517 } 1316 1518 … … 1318 1520 // in case we decide to allow nested enums 1319 1521 GuardValue( inEnumDecl ); 1320 inEnumDecl = false; 1321 } 1522 inEnumDecl = true; 1523 // don't need to fix types for enum fields 1524 } 1525 1322 1526 1323 1527 const ast::StaticAssertDecl * Resolver_new::previsit( … … 1332 1536 const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) { 1333 1537 if ( type->dimension ) { 1334 #warning should use new equivalent to Validate::SizeType rather than sizeType here 1335 ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt }; 1538 ast::ptr< ast::Type > sizeType = ast::sizeType; 1336 1539 ast::mutate_field( 1337 1540 type, &PtrType::dimension, … … 1454 1657 if ( throwStmt->expr ) { 1455 1658 const ast::StructDecl * exceptionDecl = 1456 symtab.lookupStruct( "__cfa abi_ehm__base_exception_t" );1659 symtab.lookupStruct( "__cfaehm_base_exception_t" ); 1457 1660 assert( exceptionDecl ); 1458 1661 ast::ptr< ast::Type > exceptType = … … 1466 1669 1467 1670 const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) { 1671 // Until we are very sure this invarent (ifs that move between passes have thenPart) 1672 // holds, check it. This allows a check for when to decode the mangling. 1673 if ( auto ifStmt = catchStmt->body.as<ast::IfStmt>() ) { 1674 assert( ifStmt->thenPart ); 1675 } 1676 // Encode the catchStmt so the condition can see the declaration. 1468 1677 if ( catchStmt->cond ) { 1469 ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool }; 1470 catchStmt = ast::mutate_field( 1471 catchStmt, &ast::CatchStmt::cond, 1472 findSingleExpression( catchStmt->cond, boolType, symtab ) ); 1678 ast::CatchStmt * stmt = mutate( catchStmt ); 1679 stmt->body = new ast::IfStmt( stmt->location, stmt->cond, nullptr, stmt->body ); 1680 stmt->cond = nullptr; 1681 return stmt; 1682 } 1683 return catchStmt; 1684 } 1685 1686 const ast::CatchStmt * Resolver_new::postvisit( const ast::CatchStmt * catchStmt ) { 1687 // Decode the catchStmt so everything is stored properly. 1688 const ast::IfStmt * ifStmt = catchStmt->body.as<ast::IfStmt>(); 1689 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) { 1690 assert( ifStmt->cond ); 1691 assert( ifStmt->elsePart ); 1692 ast::CatchStmt * stmt = ast::mutate( catchStmt ); 1693 stmt->cond = ifStmt->cond; 1694 stmt->body = ifStmt->elsePart; 1695 // ifStmt should be implicately deleted here. 1696 return stmt; 1473 1697 } 1474 1698 return catchStmt; … … 1587 1811 // Check if the argument matches the parameter type in the current 1588 1812 // scope 1589 ast::ptr< ast::Type > paramType = (*param)->get_type();1813 // ast::ptr< ast::Type > paramType = (*param)->get_type(); 1590 1814 if ( 1591 1815 ! unify( 1592 arg->expr->result, paramType, resultEnv, need, have, open,1816 arg->expr->result, *param, resultEnv, need, have, open, 1593 1817 symtab ) 1594 1818 ) { … … 1597 1821 ss << "candidate function not viable: no known conversion " 1598 1822 "from '"; 1599 ast::print( ss, (*param)->get_type());1823 ast::print( ss, *param ); 1600 1824 ss << "' to '"; 1601 1825 ast::print( ss, arg->expr->result ); … … 1727 1951 } 1728 1952 1953 const ast::WithStmt * Resolver_new::previsit( const ast::WithStmt * withStmt ) { 1954 auto mutStmt = mutate(withStmt); 1955 resolveWithExprs(mutStmt->exprs, stmtsToAddBefore); 1956 return mutStmt; 1957 } 1958 1959 void Resolver_new::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) { 1960 for (auto & expr : exprs) { 1961 // only struct- and union-typed expressions are viable candidates 1962 expr = findKindExpression( expr, symtab, structOrUnion, "with expression" ); 1963 1964 // if with expression might be impure, create a temporary so that it is evaluated once 1965 if ( Tuples::maybeImpure( expr ) ) { 1966 static UniqueName tmpNamer( "_with_tmp_" ); 1967 const CodeLocation loc = expr->location; 1968 auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) ); 1969 expr = new ast::VariableExpr( loc, tmp ); 1970 stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) ); 1971 if ( InitTweak::isConstructable( tmp->type ) ) { 1972 // generate ctor/dtor and resolve them 1973 tmp->init = InitTweak::genCtorInit( loc, tmp ); 1974 } 1975 // since tmp is freshly created, this should modify tmp in-place 1976 tmp->accept( *visitor ); 1977 } 1978 } 1979 } 1729 1980 1730 1981 … … 1822 2073 } 1823 2074 2075 // suppress error on autogen functions and mark invalid autogen as deleted. 2076 bool Resolver_new::on_error(ast::ptr<ast::Decl> & decl) { 2077 if (auto functionDecl = decl.as<ast::FunctionDecl>()) { 2078 // xxx - can intrinsic gen ever fail? 2079 if (functionDecl->linkage == ast::Linkage::AutoGen) { 2080 auto mutDecl = mutate(functionDecl); 2081 mutDecl->isDeleted = true; 2082 mutDecl->stmts = nullptr; 2083 decl = mutDecl; 2084 return false; 2085 } 2086 } 2087 return true; 2088 } 2089 1824 2090 } // namespace ResolvExpr 1825 2091 -
src/ResolvExpr/Resolver.h
rbdfc032 reef8dfb 35 35 class StmtExpr; 36 36 class SymbolTable; 37 struct TranslationUnit; 37 38 class Type; 38 39 class TypeEnvironment; … … 55 56 56 57 /// Checks types and binds syntactic constructs to typed representations 57 void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );58 void resolve( ast::TranslationUnit& translationUnit ); 58 59 /// Searches expr and returns the first DeletedExpr found, otherwise nullptr 59 60 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ); … … 62 63 ast::ptr< ast::Expr > resolveInVoidContext( 63 64 const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env ); 64 /// Resolve `untyped` to the single expression whose candidate is the best match for the 65 /// Resolve `untyped` to the single expression whose candidate is the best match for the 65 66 /// given type. 66 67 ast::ptr< ast::Expr > findSingleExpression( 67 68 const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab ); 69 ast::ptr< ast::Expr > findVoidExpression( 70 const ast::Expr * untyped, const ast::SymbolTable & symtab); 68 71 /// Resolves a constructor init expression 69 ast::ptr< ast::Init > resolveCtorInit( 72 ast::ptr< ast::Init > resolveCtorInit( 70 73 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab ); 71 /// Resolves a statement expression 72 ast::ptr< ast::Expr > resolveStmtExpr(74 /// Resolves a statement expression 75 const ast::Expr * resolveStmtExpr( 73 76 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab ); 74 77 } // namespace ResolvExpr -
src/ResolvExpr/SatisfyAssertions.cpp
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Mon Jun 10 17:45:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Mon Jun 10 17:45:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 13:56:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 69 69 /// Reference to a single deferred item 70 70 struct DeferRef { 71 const ast:: DeclWithType * decl;71 const ast::VariableExpr * expr; 72 72 const ast::AssertionSetValue & info; 73 73 const AssnCandidate & match; … … 77 77 /// Acts like an indexed list of DeferRef 78 78 struct DeferItem { 79 const ast:: DeclWithType * decl;79 const ast::VariableExpr * expr; 80 80 const ast::AssertionSetValue & info; 81 81 AssnCandidateList matches; 82 82 83 83 DeferItem( 84 const ast:: DeclWithType* d, const ast::AssertionSetValue & i, AssnCandidateList && ms )85 : decl( d ), info( i ), matches( std::move( ms ) ) {}84 const ast::VariableExpr * d, const ast::AssertionSetValue & i, AssnCandidateList && ms ) 85 : expr( d ), info( i ), matches( std::move( ms ) ) {} 86 86 87 87 bool empty() const { return matches.empty(); } … … 89 89 AssnCandidateList::size_type size() const { return matches.size(); } 90 90 91 DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; }91 DeferRef operator[] ( unsigned i ) const { return { expr, info, matches[i] }; } 92 92 }; 93 93 … … 138 138 void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) { 139 139 for ( auto & i : have ) { 140 if ( i.second.isUsed ) { symtab.addId( i.first ); }140 if ( i.second.isUsed ) { symtab.addId( i.first->var ); } 141 141 } 142 142 } … … 144 144 /// Binds a single assertion, updating satisfaction state 145 145 void bindAssertion( 146 const ast:: DeclWithType * decl, const ast::AssertionSetValue & info, CandidateRef & cand,146 const ast::VariableExpr * expr, const ast::AssertionSetValue & info, CandidateRef & cand, 147 147 AssnCandidate & match, InferCache & inferred 148 148 ) { … … 156 156 157 157 // place newly-inferred assertion in proper location in cache 158 inferred[ info.resnSlot ][ decl->uniqueId ] = ast::ParamEntry{159 candidate->uniqueId, candidate, match.adjType, decl->get_type(), varExpr };158 inferred[ info.resnSlot ][ expr->var->uniqueId ] = ast::ParamEntry{ 159 candidate->uniqueId, candidate, match.adjType, expr->result, varExpr }; 160 160 } 161 161 … … 167 167 // find candidates that unify with the desired type 168 168 AssnCandidateList matches; 169 for ( const ast::SymbolTable::IdData & cdata : sat.symtab.lookupId( assn.first->name ) ) { 169 170 std::vector<ast::SymbolTable::IdData> candidates; 171 auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->var->name); 172 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) { 173 // prefilter special decls by argument type, if already known 174 ast::ptr<ast::Type> thisArgType = assn.first->result.strict_as<ast::PointerType>()->base 175 .strict_as<ast::FunctionType>()->params[0] 176 .strict_as<ast::ReferenceType>()->base; 177 sat.cand->env.apply(thisArgType); 178 179 std::string otypeKey = ""; 180 if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer; 181 else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams); 182 183 candidates = sat.symtab.specialLookupId(kind, otypeKey); 184 } 185 else { 186 candidates = sat.symtab.lookupId(assn.first->var->name); 187 } 188 for ( const ast::SymbolTable::IdData & cdata : candidates ) { 170 189 const ast::DeclWithType * candidate = cdata.id; 190 191 // ignore deleted candidates. 192 // NOTE: this behavior is different from main resolver. 193 // further investigations might be needed to determine 194 // if we should implement the same rule here 195 // (i.e. error if unique best match is deleted) 196 if (candidate->isDeleted && candidate->linkage == ast::Linkage::AutoGen) continue; 171 197 172 198 // build independent unification context for candidate … … 174 200 ast::TypeEnvironment newEnv{ sat.cand->env }; 175 201 ast::OpenVarSet newOpen{ sat.cand->open }; 176 ast::ptr< ast::Type > toType = assn.first-> get_type();202 ast::ptr< ast::Type > toType = assn.first->result; 177 203 ast::ptr< ast::Type > adjType = 178 renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ) );204 renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ), GEN_USAGE, false ); 179 205 180 206 // only keep candidates which unify … … 188 214 189 215 matches.emplace_back( 190 cdata, adjType, std::move( newEnv ), std::move( newNeed ), std::move( have),216 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 191 217 std::move( newOpen ), crntResnSlot ); 192 218 } … … 229 255 InferMatcher( InferCache & inferred ) : inferred( inferred ) {} 230 256 231 const ast::Expr * post mutate( const ast::Expr * expr ) {257 const ast::Expr * postvisit( const ast::Expr * expr ) { 232 258 // Skip if no slots to find 233 if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr; 234 259 if ( !expr->inferred.hasSlots() ) return expr; 260 // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr; 261 std::vector<UniqueId> missingSlots; 235 262 // find inferred parameters for resolution slots 236 ast::InferredParams newInferred;263 ast::InferredParams * newInferred = new ast::InferredParams(); 237 264 for ( UniqueId slot : expr->inferred.resnSlots() ) { 238 265 // fail if no matching assertions found 239 266 auto it = inferred.find( slot ); 240 267 if ( it == inferred.end() ) { 241 assert(!"missing assertion"); 268 // std::cerr << "missing assertion " << slot << std::endl; 269 missingSlots.push_back(slot); 270 continue; 242 271 } 243 272 … … 245 274 for ( auto & entry : it->second ) { 246 275 // recurse on inferParams of resolved expressions 247 entry.second.expr = post mutate( entry.second.expr );248 auto res = newInferred .emplace( entry );276 entry.second.expr = postvisit( entry.second.expr ); 277 auto res = newInferred->emplace( entry ); 249 278 assert( res.second && "all assertions newly placed" ); 250 279 } … … 252 281 253 282 ast::Expr * ret = mutate( expr ); 254 ret->inferred.set_inferParams( std::move( newInferred ) ); 283 ret->inferred.set_inferParams( newInferred ); 284 if (!missingSlots.empty()) ret->inferred.resnSlots() = missingSlots; 255 285 return ret; 256 286 } … … 307 337 // compute conversion cost from satisfying decl to assertion 308 338 cost += computeConversionCost( 309 assn.match.adjType, assn. decl->get_type(), symtab, env );339 assn.match.adjType, assn.expr->result, false, symtab, env ); 310 340 311 341 // mark vars+specialization on function-type assertions … … 314 344 if ( ! func ) continue; 315 345 316 for ( const a st::DeclWithType *param : func->params ) {317 cost.decSpec( specCost( param ->get_type()) );346 for ( const auto & param : func->params ) { 347 cost.decSpec( specCost( param ) ); 318 348 } 319 349 320 350 cost.incVar( func->forall.size() ); 321 351 322 for ( const ast::TypeDecl * td : func->forall ) { 323 cost.decSpec( td->assertions.size() ); 324 } 352 cost.decSpec( func->assertions.size() ); 325 353 } 326 354 } … … 357 385 358 386 /// Limit to depth of recursion of assertion satisfaction 359 static const int recursionLimit = 7;387 static const int recursionLimit = 8; 360 388 /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of 361 389 static const int deferLimit = 10; … … 389 417 if ( it != thresholds.end() && it->second < sat.costs ) goto nextSat; 390 418 391 // make initial pass at matching assertions 392 for ( auto & assn : sat.need ) { 393 // fail early if any assertion is not satisfiable 394 if ( ! satisfyAssertion( assn, sat ) ) { 419 // should a limit be imposed? worst case here is O(n^2) but very unlikely to happen. 420 for (unsigned resetCount = 0; ; ++resetCount) { 421 ast::AssertionList next; 422 resetTyVarRenaming(); 423 // make initial pass at matching assertions 424 for ( auto & assn : sat.need ) { 425 // fail early if any assertion is not satisfiable 426 if ( ! satisfyAssertion( assn, sat ) ) { 427 next.emplace_back(assn); 428 // goto nextSat; 429 } 430 } 431 // success 432 if (next.empty()) break; 433 // fail if nothing resolves 434 else if (next.size() == sat.need.size()) { 395 435 Indenter tabs{ 3 }; 396 436 std::ostringstream ss; … … 398 438 print( ss, *sat.cand, ++tabs ); 399 439 ss << (tabs-1) << "Could not satisfy assertion:\n"; 400 ast::print( ss, assn.first, tabs );440 ast::print( ss, next[0].first, tabs ); 401 441 402 442 errors.emplace_back( ss.str() ); 403 443 goto nextSat; 404 444 } 445 sat.need = std::move(next); 405 446 } 406 447 … … 421 462 ss << (tabs-1) << "Too many non-unique satisfying assignments for assertions:\n"; 422 463 for ( const auto & d : sat.deferred ) { 423 ast::print( ss, d. decl, tabs );464 ast::print( ss, d.expr, tabs ); 424 465 } 425 466 … … 439 480 ss << (tabs-1) << "No mutually-compatible satisfaction for assertions:\n"; 440 481 for ( const auto& d : sat.deferred ) { 441 ast::print( ss, d. decl, tabs );482 ast::print( ss, d.expr, tabs ); 442 483 } 443 484 … … 471 512 nextNewNeed.insert( match.need.begin(), match.need.end() ); 472 513 473 bindAssertion( r. decl, r.info, nextCand, match, nextInferred );514 bindAssertion( r.expr, r.info, nextCand, match, nextInferred ); 474 515 } 475 516 -
src/ResolvExpr/SatisfyAssertions.hpp
rbdfc032 reef8dfb 27 27 namespace ResolvExpr { 28 28 29 /// Recursively satisfies all assertions provided in a candidate; returns true if succeeds 30 void satisfyAssertions( 31 CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 29 /// Recursively satisfies all assertions provided in a candidate 30 /// returns true if it has been run (candidate has any assertions) 31 void satisfyAssertions( 32 CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 32 33 std::vector<std::string> & errors ); 33 34 -
src/ResolvExpr/SpecCost.cc
rbdfc032 reef8dfb 10 10 // Created On : Tue Oct 02 15:50:00 2018 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Jun 19 10:43:00 2019 13 // Update Count : 2 14 // 15 12 // Last Modified On : Wed Jul 3 11:07:00 2019 13 // Update Count : 3 14 // 15 16 #include <cassert> 16 17 #include <limits> 17 18 #include <list> … … 129 130 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 130 131 132 #warning Should use a standard maybe_accept 133 void maybe_accept( ast::Type const * type ) { 134 if ( type ) { 135 auto node = type->accept( *visitor ); 136 assert( node == nullptr || node == type ); 137 } 138 } 139 131 140 // Update the minimum to the new lowest non-none value. 132 141 template<typename T> … … 134 143 for ( const auto & node : list ) { 135 144 count = -1; 136 ma pper( node )->accept( *visitor);145 maybe_accept( mapper( node ) ); 137 146 if ( count != -1 && count < minimum ) minimum = count; 138 147 } … … 169 178 void previsit( const ast::FunctionType * fty ) { 170 179 int minCount = std::numeric_limits<int>::max(); 171 updateMinimumPresent( minCount, fty->params, decl_type);172 updateMinimumPresent( minCount, fty->returns, decl_type);180 updateMinimumPresent( minCount, fty->params, type_deref ); 181 updateMinimumPresent( minCount, fty->returns, type_deref ); 173 182 // Add another level to minCount if set. 174 183 count = toNoneOrInc( minCount ); … … 208 217 } 209 218 ast::Pass<SpecCounter> counter; 210 type->accept( *counter.pass.visitor );211 return counter. pass.get_count();219 type->accept( counter ); 220 return counter.core.get_count(); 212 221 } 213 222 -
src/ResolvExpr/TypeEnvironment.cc
rbdfc032 reef8dfb 20 20 #include <utility> // for pair, move 21 21 22 #include "CompilationState.h" // for deterministic_output 22 23 #include "Common/utility.h" // for maybeClone 23 24 #include "SynTree/Type.h" // for Type, FunctionType, Type::Fora... … … 106 107 107 108 void EqvClass::print( std::ostream &os, Indenter indent ) const { 108 os << "( "; 109 std::copy( vars.begin(), vars.end(), std::ostream_iterator< std::string >( os, " " ) ); 109 os << "("; 110 bool first = true; 111 for(const auto & var : vars) { 112 if(first) first = false; 113 else os << " "; 114 if( deterministic_output && isUnboundType(var) ) os << "[unbound]"; 115 else os << var; 116 } 110 117 os << ")"; 111 118 if ( type ) { … … 235 242 // check safely bindable 236 243 if ( r.type && occursIn( r.type, s.vars.begin(), s.vars.end(), *this ) ) return false; 237 244 238 245 // merge classes in 239 246 r.vars.insert( s.vars.begin(), s.vars.end() ); -
src/ResolvExpr/TypeEnvironment.h
rbdfc032 reef8dfb 149 149 iterator end() const { return env.end(); } 150 150 151 auto size() const { return env.size(); } 152 151 153 private: 152 154 ClassList env; -
src/ResolvExpr/Unify.cc
rbdfc032 reef8dfb 25 25 #include <vector> 26 26 27 #include "AST/Copy.hpp" 27 28 #include "AST/Decl.hpp" 28 29 #include "AST/Node.hpp" 29 30 #include "AST/Pass.hpp" 31 #include "AST/Print.hpp" 30 32 #include "AST/Type.hpp" 31 33 #include "AST/TypeEnvironment.hpp" … … 135 137 findOpenVars( newSecond, open, closed, need, have, FirstOpen ); 136 138 137 return unifyExact( 138 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 140 } 140 141 … … 148 149 newFirst->get_qualifiers() = Type::Qualifiers(); 149 150 newSecond->get_qualifiers() = Type::Qualifiers(); 150 /// std::cerr << "first is "; 151 /// first->print( std::cerr ); 152 /// std::cerr << std::endl << "second is "; 153 /// second->print( std::cerr ); 154 /// std::cerr << std::endl << "newFirst is "; 155 /// newFirst->print( std::cerr ); 156 /// std::cerr << std::endl << "newSecond is "; 157 /// newSecond->print( std::cerr ); 158 /// std::cerr << std::endl; 151 159 152 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 160 153 delete newFirst; … … 170 163 ast::AssertionSet need, have; 171 164 172 ast::ptr<ast::Type> newFirst{ first }, newSecond{ second }; 173 env.apply( newFirst ); 174 env.apply( newSecond ); 175 reset_qualifiers( newFirst ); 176 reset_qualifiers( newSecond ); 165 ast::Type * newFirst = shallowCopy( first ); 166 ast::Type * newSecond = shallowCopy( second ); 167 newFirst ->qualifiers = {}; 168 newSecond->qualifiers = {}; 169 ast::ptr< ast::Type > t1_(newFirst ); 170 ast::ptr< ast::Type > t2_(newSecond); 171 172 ast::ptr< ast::Type > subFirst = env.apply(newFirst).node; 173 ast::ptr< ast::Type > subSecond = env.apply(newSecond).node; 177 174 178 175 return unifyExact( 179 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 176 subFirst, 177 subSecond, 178 newEnv, need, have, open, noWiden(), symtab ); 180 179 } 181 180 … … 326 325 327 326 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) { 328 /// std::cerr << "assertion set is" << std::endl;329 /// printAssertionSet( assertions, std::cerr, 8 );330 /// std::cerr << "looking for ";331 /// assert->print( std::cerr );332 /// std::cerr << std::endl;333 327 AssertionSet::iterator i = assertions.find( assert ); 334 328 if ( i != assertions.end() ) { 335 /// std::cerr << "found it!" << std::endl;336 329 i->second.isUsed = true; 337 330 } // if … … 402 395 403 396 template< typename Iterator1, typename Iterator2 > 404 bool unify DeclList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {397 bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 405 398 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); }; 406 399 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) { … … 496 489 || flatOther->isTtype() 497 490 ) { 498 if ( unify DeclList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {499 if ( unify DeclList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {491 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 492 if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 500 493 501 494 // the original types must be used in mark assertions, since pointer comparisons are used … … 709 702 const ast::SymbolTable & symtab; 710 703 public: 704 static size_t traceId; 711 705 bool result; 712 706 … … 773 767 /// If this isn't done when satifying ttype assertions, then argument lists can have 774 768 /// different size and structure when they should be compatible. 775 struct TtypeExpander_new : public ast::WithShortCircuiting {769 struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor { 776 770 ast::TypeEnvironment & tenv; 777 771 … … 779 773 780 774 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) { 781 if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name) ) {775 if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) { 782 776 // expand ttype parameter into its actual type 783 777 if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) { … … 790 784 791 785 /// returns flattened version of `src` 792 static std::vector< ast::ptr< ast:: DeclWithType > > flattenList(793 const std::vector< ast::ptr< ast:: DeclWithType > > & src, ast::TypeEnvironment & env786 static std::vector< ast::ptr< ast::Type > > flattenList( 787 const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env 794 788 ) { 795 std::vector< ast::ptr< ast:: DeclWithType > > dst;789 std::vector< ast::ptr< ast::Type > > dst; 796 790 dst.reserve( src.size() ); 797 for ( const a st::DeclWithType *d : src ) {791 for ( const auto & d : src ) { 798 792 ast::Pass<TtypeExpander_new> expander{ env }; 799 d = d->accept( expander ); 800 auto types = flatten( d->get_type() ); 793 // TtypeExpander pass is impure (may mutate nodes in place) 794 // need to make nodes shared to prevent accidental mutation 795 ast::ptr<ast::Type> dc = d->accept(expander); 796 auto types = flatten( dc ); 801 797 for ( ast::ptr< ast::Type > & t : types ) { 802 798 // outermost const, volatile, _Atomic qualifiers in parameters should not play … … 807 803 // requirements than a non-mutex function 808 804 remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic ); 809 dst.emplace_back( new ast::ObjectDecl{ d->location, "", t });805 dst.emplace_back( t ); 810 806 } 811 807 } … … 815 811 /// Creates a tuple type based on a list of DeclWithType 816 812 template< typename Iter > 817 static ast::ptr< ast::Type > tupleFromDecls( Iter crnt, Iter end ) {813 static const ast::Type * tupleFromTypes( Iter crnt, Iter end ) { 818 814 std::vector< ast::ptr< ast::Type > > types; 819 815 while ( crnt != end ) { 820 816 // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure 821 817 // that this results in a flat tuple 822 flatten( (*crnt)->get_type(), types );818 flatten( *crnt, types ); 823 819 824 820 ++crnt; 825 821 } 826 822 827 return { new ast::TupleType{ std::move(types) }};823 return new ast::TupleType{ std::move(types) }; 828 824 } 829 825 830 826 template< typename Iter > 831 static bool unify DeclList(827 static bool unifyTypeList( 832 828 Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env, 833 829 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open, … … 835 831 ) { 836 832 while ( crnt1 != end1 && crnt2 != end2 ) { 837 const ast::Type * t1 = (*crnt1)->get_type();838 const ast::Type * t2 = (*crnt2)->get_type();833 const ast::Type * t1 = *crnt1; 834 const ast::Type * t2 = *crnt2; 839 835 bool isTuple1 = Tuples::isTtype( t1 ); 840 836 bool isTuple2 = Tuples::isTtype( t2 ); … … 844 840 // combine remainder of list2, then unify 845 841 return unifyExact( 846 t1, tupleFrom Decls( crnt2, end2 ), env, need, have, open,842 t1, tupleFromTypes( crnt2, end2 ), env, need, have, open, 847 843 noWiden(), symtab ); 848 844 } else if ( ! isTuple1 && isTuple2 ) { 849 845 // combine remainder of list1, then unify 850 846 return unifyExact( 851 tupleFrom Decls( crnt1, end1 ), t2, env, need, have, open,847 tupleFromTypes( crnt1, end1 ), t2, env, need, have, open, 852 848 noWiden(), symtab ); 853 849 } … … 864 860 if ( crnt1 != end1 ) { 865 861 // try unifying empty tuple with ttype 866 const ast::Type * t1 = (*crnt1)->get_type();862 const ast::Type * t1 = *crnt1; 867 863 if ( ! Tuples::isTtype( t1 ) ) return false; 868 864 return unifyExact( 869 t1, tupleFrom Decls( crnt2, end2 ), env, need, have, open,865 t1, tupleFromTypes( crnt2, end2 ), env, need, have, open, 870 866 noWiden(), symtab ); 871 867 } else if ( crnt2 != end2 ) { 872 868 // try unifying empty tuple with ttype 873 const ast::Type * t2 = (*crnt2)->get_type();869 const ast::Type * t2 = *crnt2; 874 870 if ( ! Tuples::isTtype( t2 ) ) return false; 875 871 return unifyExact( 876 tupleFrom Decls( crnt1, end1 ), t2, env, need, have, open,872 tupleFromTypes( crnt1, end1 ), t2, env, need, have, open, 877 873 noWiden(), symtab ); 878 874 } … … 881 877 } 882 878 883 static bool unify DeclList(884 const std::vector< ast::ptr< ast:: DeclWithType > > & list1,885 const std::vector< ast::ptr< ast:: DeclWithType > > & list2,879 static bool unifyTypeList( 880 const std::vector< ast::ptr< ast::Type > > & list1, 881 const std::vector< ast::ptr< ast::Type > > & list2, 886 882 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 887 883 const ast::OpenVarSet & open, const ast::SymbolTable & symtab 888 884 ) { 889 return unify DeclList(885 return unifyTypeList( 890 886 list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open, 891 887 symtab ); 892 888 } 893 889 894 static void markAssertionSet( ast::AssertionSet & assns, const ast:: DeclWithType* assn ) {890 static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) { 895 891 auto i = assns.find( assn ); 896 892 if ( i != assns.end() ) { … … 902 898 static void markAssertions( 903 899 ast::AssertionSet & assn1, ast::AssertionSet & assn2, 904 const ast:: ParameterizedType * type900 const ast::FunctionType * type 905 901 ) { 906 for ( const auto & tyvar : type->forall ) { 907 for ( const ast::DeclWithType * assert : tyvar->assertions ) { 908 markAssertionSet( assn1, assert ); 909 markAssertionSet( assn2, assert ); 910 } 902 for ( auto & assert : type->assertions ) { 903 markAssertionSet( assn1, assert ); 904 markAssertionSet( assn2, assert ); 911 905 } 912 906 } … … 932 926 ) return; 933 927 934 if ( ! unify DeclList( params, params2, tenv, need, have, open, symtab ) ) return;935 if ( ! unify DeclList(928 if ( ! unifyTypeList( params, params2, tenv, need, have, open, symtab ) ) return; 929 if ( ! unifyTypeList( 936 930 func->returns, func2->returns, tenv, need, have, open, symtab ) ) return; 937 931 … … 943 937 944 938 private: 945 template< typename RefType > 946 const RefType * handleRefType( const RefType * inst, const ast::Type * other ) { 939 // Returns: other, cast as XInstType 940 // Assigns this->result: whether types are compatible (up to generic parameters) 941 template< typename XInstType > 942 const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) { 947 943 // check that the other type is compatible and named the same 948 auto otherInst = dynamic_cast< const RefType * >( other );949 result = otherInst && inst->name == otherInst->name;944 auto otherInst = dynamic_cast< const XInstType * >( other ); 945 this->result = otherInst && inst->name == otherInst->name; 950 946 return otherInst; 951 947 } … … 968 964 } 969 965 970 template< typename RefType >971 void handleGenericRefType( const RefType * inst, const ast::Type * other ) {966 template< typename XInstType > 967 void handleGenericRefType( const XInstType * inst, const ast::Type * other ) { 972 968 // check that other type is compatible and named the same 973 const RefType * inst2= handleRefType( inst, other );974 if ( ! inst2) return;969 const XInstType * otherInst = handleRefType( inst, other ); 970 if ( ! this->result ) return; 975 971 976 972 // check that parameters of types unify, if any 977 973 const std::vector< ast::ptr< ast::Expr > > & params = inst->params; 978 const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;974 const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params; 979 975 980 976 auto it = params.begin(); … … 1032 1028 1033 1029 void postvisit( const ast::TypeInstType * typeInst ) { 1034 assert( open.find( typeInst->name) == open.end() );1030 assert( open.find( *typeInst ) == open.end() ); 1035 1031 handleRefType( typeInst, type2 ); 1036 1032 } … … 1038 1034 private: 1039 1035 /// Creates a tuple type based on a list of Type 1040 static ast::ptr< ast::Type >tupleFromTypes(1036 static const ast::Type * tupleFromTypes( 1041 1037 const std::vector< ast::ptr< ast::Type > > & tys 1042 1038 ) { … … 1114 1110 1115 1111 ast::Pass<TtypeExpander_new> expander{ tenv }; 1112 1116 1113 const ast::Type * flat = tuple->accept( expander ); 1117 1114 const ast::Type * flat2 = tuple2->accept( expander ); … … 1140 1137 }; 1141 1138 1139 // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new"); 1142 1140 bool unify( 1143 1141 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, … … 1171 1169 auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 ); 1172 1170 ast::OpenVarSet::const_iterator 1173 entry1 = var1 ? open.find( var1->name) : open.end(),1174 entry2 = var2 ? open.find( var2->name) : open.end();1171 entry1 = var1 ? open.find( *var1 ) : open.end(), 1172 entry2 = var2 ? open.find( *var2 ) : open.end(); 1175 1173 bool isopen1 = entry1 != open.end(); 1176 1174 bool isopen2 = entry2 != open.end(); … … 1188 1186 ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab }; 1189 1187 type1->accept( comparator ); 1190 return comparator. pass.result;1188 return comparator.core.result; 1191 1189 } 1192 1190 } … … 1202 1200 // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and 1203 1201 // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1 1204 ast::ptr<ast::Type> t1{ type1 }, t2{ type2 }; 1205 reset_qualifiers( t1 ); 1206 reset_qualifiers( t2 ); 1202 ast::Type * t1 = shallowCopy(type1.get()); 1203 ast::Type * t2 = shallowCopy(type2.get()); 1204 t1->qualifiers = {}; 1205 t2->qualifiers = {}; 1206 ast::ptr< ast::Type > t1_(t1); 1207 ast::ptr< ast::Type > t2_(t2); 1207 1208 1208 1209 if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) { 1209 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1210 1211 1210 // if exact unification on unqualified types, try to merge qualifiers 1212 1211 if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) { 1213 common = type1;1214 reset_qualifiers( common, q1 | q2 );1212 t1->qualifiers = q1 | q2; 1213 common = t1; 1215 1214 return true; 1216 1215 } else { … … 1219 1218 1220 1219 } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) { 1221 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1222 1223 1220 // no exact unification, but common type 1224 reset_qualifiers( common, q1 | q2 ); 1221 auto c = shallowCopy(common.get()); 1222 c->qualifiers = q1 | q2; 1223 common = c; 1225 1224 return true; 1226 1225 } else { … … 1231 1230 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) { 1232 1231 if ( func->returns.empty() ) return new ast::VoidType{}; 1233 if ( func->returns.size() == 1 ) return func->returns[0] ->get_type();1232 if ( func->returns.size() == 1 ) return func->returns[0]; 1234 1233 1235 1234 std::vector<ast::ptr<ast::Type>> tys; 1236 for ( const a st::DeclWithType *decl : func->returns ) {1237 tys.emplace_back( decl ->get_type());1235 for ( const auto & decl : func->returns ) { 1236 tys.emplace_back( decl ); 1238 1237 } 1239 1238 return new ast::TupleType{ std::move(tys) }; -
src/ResolvExpr/module.mk
rbdfc032 reef8dfb 19 19 ResolvExpr/Alternative.cc \ 20 20 ResolvExpr/AlternativeFinder.cc \ 21 ResolvExpr/AlternativeFinder.h \ 22 ResolvExpr/Alternative.h \ 21 23 ResolvExpr/Candidate.cpp \ 22 24 ResolvExpr/CandidateFinder.cpp \ 25 ResolvExpr/CandidateFinder.hpp \ 26 ResolvExpr/Candidate.hpp \ 23 27 ResolvExpr/CastCost.cc \ 24 28 ResolvExpr/CommonType.cc \ 25 29 ResolvExpr/ConversionCost.cc \ 30 ResolvExpr/ConversionCost.h \ 31 ResolvExpr/Cost.h \ 26 32 ResolvExpr/CurrentObject.cc \ 33 ResolvExpr/CurrentObject.h \ 27 34 ResolvExpr/ExplodedActual.cc \ 35 ResolvExpr/ExplodedActual.h \ 28 36 ResolvExpr/ExplodedArg.cpp \ 37 ResolvExpr/ExplodedArg.hpp \ 29 38 ResolvExpr/FindOpenVars.cc \ 39 ResolvExpr/FindOpenVars.h \ 30 40 ResolvExpr/Occurs.cc \ 31 41 ResolvExpr/PolyCost.cc \ … … 33 43 ResolvExpr/PtrsCastable.cc \ 34 44 ResolvExpr/RenameVars.cc \ 45 ResolvExpr/RenameVars.h \ 35 46 ResolvExpr/ResolveAssertions.cc \ 47 ResolvExpr/ResolveAssertions.h \ 36 48 ResolvExpr/Resolver.cc \ 49 ResolvExpr/Resolver.h \ 37 50 ResolvExpr/ResolveTypeof.cc \ 51 ResolvExpr/ResolveTypeof.h \ 52 ResolvExpr/ResolvMode.h \ 38 53 ResolvExpr/SatisfyAssertions.cpp \ 54 ResolvExpr/SatisfyAssertions.hpp \ 39 55 ResolvExpr/SpecCost.cc \ 40 56 ResolvExpr/TypeEnvironment.cc \ 41 ResolvExpr/Unify.cc 57 ResolvExpr/TypeEnvironment.h \ 58 ResolvExpr/typeops.h \ 59 ResolvExpr/Unify.cc \ 60 ResolvExpr/Unify.h \ 61 ResolvExpr/WidenMode.h 42 62 43 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc 63 64 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc ResolvExpr/AlternativePrinter.h 44 65 SRCDEMANGLE += $(SRC_RESOLVEXPR) -
src/ResolvExpr/typeops.h
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 07:28:22 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:36:00 201913 // Update Count : 512 // Last Modified On : Tue Oct 1 09:45:00 2019 13 // Update Count : 6 14 14 // 15 15 … … 83 83 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 84 84 Cost castCost( 85 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,86 const ast:: TypeEnvironment & env );85 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 86 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 87 87 88 88 // in ConversionCost.cc … … 90 90 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 91 91 Cost conversionCost( 92 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,93 const ast:: TypeEnvironment & env );92 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 93 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 94 94 95 95 // in AlternativeFinder.cc
Note:
See TracChangeset
for help on using the changeset viewer.