| [51587aa] | 1 | // | 
|---|
|  | 2 | // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo | 
|---|
|  | 3 | // | 
|---|
|  | 4 | // The contents of this file are covered under the licence agreement in the | 
|---|
|  | 5 | // file "LICENCE" distributed with Cforall. | 
|---|
|  | 6 | // | 
|---|
| [c92bdcc] | 7 | // GenPoly.cpp -- General GenPoly utilities. | 
|---|
| [51587aa] | 8 | // | 
|---|
|  | 9 | // Author           : Richard C. Bilson | 
|---|
|  | 10 | // Created On       : Mon May 18 07:44:20 2015 | 
|---|
| [3606fe4] | 11 | // Last Modified By : Andrew Beach | 
|---|
| [63d1ebe] | 12 | // Last Modified On : Mon Oct 24 15:19:00 2022 | 
|---|
|  | 13 | // Update Count     : 17 | 
|---|
| [51587aa] | 14 | // | 
|---|
| [51b73452] | 15 |  | 
|---|
| [c92bdcc] | 16 | #include "GenPoly.hpp" | 
|---|
| [ffad73a] | 17 |  | 
|---|
| [c92bdcc] | 18 | #include <cassert>                        // for assertf, assert | 
|---|
|  | 19 | #include <iostream>                       // for operator<<, ostream, basic_... | 
|---|
|  | 20 | #include <iterator>                       // for back_insert_iterator, back_... | 
|---|
|  | 21 | #include <list>                           // for list, _List_iterator, list<... | 
|---|
|  | 22 | #include <typeindex>                      // for type_index | 
|---|
|  | 23 | #include <utility>                        // for pair | 
|---|
|  | 24 | #include <vector>                         // for vector | 
|---|
| [08fc48f] | 25 |  | 
|---|
| [a0d1f1c] | 26 | #include "AST/Expr.hpp" | 
|---|
| [d76c588] | 27 | #include "AST/Type.hpp" | 
|---|
| [a0d1f1c] | 28 | #include "AST/TypeSubstitution.hpp" | 
|---|
| [f9ad69d] | 29 | #include "Common/Eval.hpp"                // for eval | 
|---|
| [c92bdcc] | 30 | #include "GenPoly/ErasableScopedMap.hpp"  // for ErasableScopedMap<>::const_... | 
|---|
|  | 31 | #include "ResolvExpr/Typeops.hpp"         // for flatten | 
|---|
| [51b73452] | 32 |  | 
|---|
| [b1a6d6b] | 33 | using namespace std; | 
|---|
| [51b73452] | 34 |  | 
|---|
|  | 35 | namespace GenPoly { | 
|---|
| [b8b5535] | 36 |  | 
|---|
|  | 37 | namespace { | 
|---|
|  | 38 | /// Checks a parameter list for polymorphic parameters; will substitute according to env if present. | 
|---|
|  | 39 | bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) { | 
|---|
|  | 40 | for ( auto & param : params ) { | 
|---|
|  | 41 | auto paramType = param.as<ast::TypeExpr>(); | 
|---|
|  | 42 | assertf( paramType, "Aggregate parameters should be type expressions" ); | 
|---|
|  | 43 | if ( isPolyType( paramType->type, env ) ) return true; | 
|---|
| [490fb92e] | 44 | } | 
|---|
| [b8b5535] | 45 | return false; | 
|---|
|  | 46 | } | 
|---|
| [490fb92e] | 47 |  | 
|---|
| [b8b5535] | 48 | /// Checks a parameter list for polymorphic parameters from typeVars; will substitute according to env if present. | 
|---|
|  | 49 | bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) { | 
|---|
|  | 50 | for ( auto & param : params ) { | 
|---|
|  | 51 | auto paramType = param.as<ast::TypeExpr>(); | 
|---|
|  | 52 | assertf( paramType, "Aggregate parameters should be type expressions" ); | 
|---|
|  | 53 | if ( isPolyType( paramType->type, typeVars, env ) ) return true; | 
|---|
| [3df4cd9] | 54 | } | 
|---|
| [b8b5535] | 55 | return false; | 
|---|
|  | 56 | } | 
|---|
| [3df4cd9] | 57 |  | 
|---|
| [b8b5535] | 58 | /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present. | 
|---|
|  | 59 | bool hasDynParams( | 
|---|
|  | 60 | const std::vector<ast::ptr<ast::Expr>> & params, | 
|---|
|  | 61 | const TypeVarMap & typeVars, | 
|---|
|  | 62 | const ast::TypeSubstitution * subst ) { | 
|---|
|  | 63 | for ( ast::ptr<ast::Expr> const & paramExpr : params ) { | 
|---|
|  | 64 | auto param = paramExpr.as<ast::TypeExpr>(); | 
|---|
|  | 65 | assertf( param, "Aggregate parameters should be type expressions." ); | 
|---|
|  | 66 | if ( isDynType( param->type.get(), typeVars, subst ) ) { | 
|---|
|  | 67 | return true; | 
|---|
| [3606fe4] | 68 | } | 
|---|
|  | 69 | } | 
|---|
| [b8b5535] | 70 | return false; | 
|---|
| [4da152a] | 71 | } | 
|---|
| [b8b5535] | 72 | } // namespace | 
|---|
| [4da152a] | 73 |  | 
|---|
| [b8b5535] | 74 | const ast::Type * replaceTypeInst( const ast::Type * type, const ast::TypeSubstitution * env ) { | 
|---|
|  | 75 | if ( !env ) return type; | 
|---|
|  | 76 | if ( auto typeInst = dynamic_cast<const ast::TypeInstType*>( type ) ) { | 
|---|
|  | 77 | if ( auto newType = env->lookup( typeInst ) ) return newType; | 
|---|
| [490fb92e] | 78 | } | 
|---|
| [b8b5535] | 79 | return type; | 
|---|
|  | 80 | } | 
|---|
| [490fb92e] | 81 |  | 
|---|
| [b8b5535] | 82 | const ast::Type * isPolyType( const ast::Type * type, const ast::TypeSubstitution * subst ) { | 
|---|
|  | 83 | type = replaceTypeInst( type, subst ); | 
|---|
|  | 84 |  | 
|---|
|  | 85 | if ( dynamic_cast< const ast::TypeInstType * >( type ) ) { | 
|---|
|  | 86 | // This case is where the two variants of isPolyType differ. | 
|---|
|  | 87 | return type; | 
|---|
|  | 88 | } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { | 
|---|
|  | 89 | return isPolyType( arrayType->base, subst ); | 
|---|
|  | 90 | } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { | 
|---|
|  | 91 | if ( hasPolyParams( structType->params, subst ) ) return type; | 
|---|
|  | 92 | } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { | 
|---|
|  | 93 | if ( hasPolyParams( unionType->params, subst ) ) return type; | 
|---|
| [490fb92e] | 94 | } | 
|---|
| [b8b5535] | 95 | return nullptr; | 
|---|
|  | 96 | } | 
|---|
| [490fb92e] | 97 |  | 
|---|
| [c8837e5] | 98 | const ast::Type * isPolyType( const ast::Type * type, | 
|---|
|  | 99 | const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { | 
|---|
|  | 100 | type = replaceTypeInst( type, subst ); | 
|---|
|  | 101 |  | 
|---|
|  | 102 | if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { | 
|---|
| [e9b5043] | 103 | if ( typeVars.contains( *inst ) ) return type; | 
|---|
| [c8837e5] | 104 | } else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) { | 
|---|
| [3df4cd9] | 105 | return isPolyType( array->base, typeVars, subst ); | 
|---|
| [c8837e5] | 106 | } else if ( auto sue = dynamic_cast< const ast::StructInstType * >( type ) ) { | 
|---|
| [3df4cd9] | 107 | if ( hasPolyParams( sue->params, typeVars, subst ) ) return type; | 
|---|
| [c8837e5] | 108 | } else if ( auto sue = dynamic_cast< const ast::UnionInstType * >( type ) ) { | 
|---|
| [3df4cd9] | 109 | if ( hasPolyParams( sue->params, typeVars, subst ) ) return type; | 
|---|
| [c8837e5] | 110 | } | 
|---|
|  | 111 | return nullptr; | 
|---|
|  | 112 | } | 
|---|
|  | 113 |  | 
|---|
|  | 114 | const ast::BaseInstType * isDynType( | 
|---|
|  | 115 | const ast::Type * type, const TypeVarMap & typeVars, | 
|---|
|  | 116 | const ast::TypeSubstitution * subst ) { | 
|---|
|  | 117 | type = replaceTypeInst( type, subst ); | 
|---|
|  | 118 |  | 
|---|
|  | 119 | if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) { | 
|---|
| [63d1ebe] | 120 | auto var = typeVars.find( *inst ); | 
|---|
| [c8837e5] | 121 | if ( var != typeVars.end() && var->second.isComplete ) { | 
|---|
| [75f6a5f] | 122 | return inst; | 
|---|
| [3606fe4] | 123 | } | 
|---|
| [c8837e5] | 124 | } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) { | 
|---|
| [b8b5535] | 125 | if ( hasDynParams( inst->params, typeVars, subst ) ) return inst; | 
|---|
| [c8837e5] | 126 | } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) { | 
|---|
| [b8b5535] | 127 | if ( hasDynParams( inst->params, typeVars, subst ) ) return inst; | 
|---|
| [3606fe4] | 128 | } | 
|---|
| [c8837e5] | 129 | return nullptr; | 
|---|
|  | 130 | } | 
|---|
| [3606fe4] | 131 |  | 
|---|
| [c8837e5] | 132 | const ast::BaseInstType *isDynRet( | 
|---|
|  | 133 | const ast::FunctionType * type, const TypeVarMap & typeVars ) { | 
|---|
|  | 134 | if ( type->returns.empty() ) return nullptr; | 
|---|
|  | 135 |  | 
|---|
|  | 136 | return isDynType( type->returns.front(), typeVars ); | 
|---|
|  | 137 | } | 
|---|
|  | 138 |  | 
|---|
| [c97b448] | 139 | const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) { | 
|---|
|  | 140 | if ( func->returns.empty() ) return nullptr; | 
|---|
|  | 141 |  | 
|---|
| [52a5262e] | 142 | TypeVarMap forallTypes; | 
|---|
| [c97b448] | 143 | makeTypeVarMap( func, forallTypes ); | 
|---|
|  | 144 | return isDynType( func->returns.front(), forallTypes ); | 
|---|
|  | 145 | } | 
|---|
|  | 146 |  | 
|---|
| [c8837e5] | 147 | bool needsAdapter( | 
|---|
|  | 148 | ast::FunctionType const * adaptee, const TypeVarMap & typeVars ) { | 
|---|
|  | 149 | if ( isDynRet( adaptee, typeVars ) ) return true; | 
|---|
|  | 150 |  | 
|---|
|  | 151 | for ( auto param : adaptee->params ) { | 
|---|
|  | 152 | if ( isDynType( param, typeVars ) ) { | 
|---|
|  | 153 | return true; | 
|---|
|  | 154 | } | 
|---|
|  | 155 | } | 
|---|
|  | 156 | return false; | 
|---|
|  | 157 | } | 
|---|
|  | 158 |  | 
|---|
| [c97b448] | 159 | const ast::Type * isPolyPtr( | 
|---|
|  | 160 | const ast::Type * type, const TypeVarMap & typeVars, | 
|---|
|  | 161 | const ast::TypeSubstitution * typeSubs ) { | 
|---|
|  | 162 | type = replaceTypeInst( type, typeSubs ); | 
|---|
|  | 163 |  | 
|---|
|  | 164 | if ( auto * ptr = dynamic_cast<ast::PointerType const *>( type ) ) { | 
|---|
|  | 165 | return isPolyType( ptr->base, typeVars, typeSubs ); | 
|---|
|  | 166 | } | 
|---|
|  | 167 | return nullptr; | 
|---|
|  | 168 | } | 
|---|
|  | 169 |  | 
|---|
| [c8837e5] | 170 | ast::Type const * hasPolyBase( | 
|---|
|  | 171 | ast::Type const * type, const TypeVarMap & typeVars, | 
|---|
|  | 172 | int * levels, const ast::TypeSubstitution * subst ) { | 
|---|
|  | 173 | int level_count = 0; | 
|---|
|  | 174 |  | 
|---|
|  | 175 | while ( true ) { | 
|---|
|  | 176 | type = replaceTypeInst( type, subst ); | 
|---|
|  | 177 |  | 
|---|
|  | 178 | if ( auto ptr = dynamic_cast<ast::PointerType const *>( type ) ) { | 
|---|
|  | 179 | type = ptr->base; | 
|---|
|  | 180 | ++level_count; | 
|---|
|  | 181 | } else { | 
|---|
|  | 182 | break; | 
|---|
|  | 183 | } | 
|---|
|  | 184 | } | 
|---|
|  | 185 |  | 
|---|
|  | 186 | if ( nullptr != levels ) { *levels = level_count; } | 
|---|
|  | 187 | return isPolyType( type, typeVars, subst ); | 
|---|
|  | 188 | } | 
|---|
|  | 189 |  | 
|---|
| [b8b5535] | 190 | const ast::FunctionType * getFunctionType( const ast::Type * ty ) { | 
|---|
|  | 191 | if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) { | 
|---|
|  | 192 | return pty->base.as< ast::FunctionType >(); | 
|---|
|  | 193 | } else { | 
|---|
|  | 194 | return dynamic_cast< const ast::FunctionType * >( ty ); | 
|---|
| [d76c588] | 195 | } | 
|---|
| [b8b5535] | 196 | } | 
|---|
| [d76c588] | 197 |  | 
|---|
| [b8b5535] | 198 | namespace { | 
|---|
|  | 199 | /// Checks if is a pointer to D | 
|---|
|  | 200 | template<typename D, typename B> | 
|---|
|  | 201 | bool is( const B* p ) { return type_index{typeid(D)} == type_index{typeid(*p)}; } | 
|---|
| [5a3ac84] | 202 |  | 
|---|
| [b8b5535] | 203 | /// Converts to a pointer to D without checking for safety | 
|---|
|  | 204 | template<typename D, typename B> | 
|---|
|  | 205 | inline D* as( B* p ) { return reinterpret_cast<D*>(p); } | 
|---|
|  | 206 |  | 
|---|
|  | 207 | template<typename D, typename B> | 
|---|
|  | 208 | inline D const * as( B const * p ) { | 
|---|
|  | 209 | return reinterpret_cast<D const *>( p ); | 
|---|
|  | 210 | } | 
|---|
| [5a3ac84] | 211 |  | 
|---|
| [b8b5535] | 212 | /// Flattens a list of types. | 
|---|
|  | 213 | void flattenList( vector<ast::ptr<ast::Type>> const & src, | 
|---|
|  | 214 | vector<ast::ptr<ast::Type>> & out ) { | 
|---|
|  | 215 | for ( auto const & type : src ) { | 
|---|
|  | 216 | ResolvExpr::flatten( type, out ); | 
|---|
| [3606fe4] | 217 | } | 
|---|
| [b8b5535] | 218 | } | 
|---|
| [3606fe4] | 219 |  | 
|---|
| [b8b5535] | 220 | bool paramListsPolyCompatible( | 
|---|
|  | 221 | std::vector<ast::ptr<ast::Expr>> const & lparams, | 
|---|
|  | 222 | std::vector<ast::ptr<ast::Expr>> const & rparams ) { | 
|---|
|  | 223 | if ( lparams.size() != rparams.size() ) { | 
|---|
|  | 224 | return false; | 
|---|
| [3606fe4] | 225 | } | 
|---|
|  | 226 |  | 
|---|
| [b8b5535] | 227 | for ( auto lparam = lparams.begin(), rparam = rparams.begin() ; | 
|---|
|  | 228 | lparam != lparams.end() ; ++lparam, ++rparam ) { | 
|---|
|  | 229 | ast::TypeExpr const * lexpr = lparam->as<ast::TypeExpr>(); | 
|---|
|  | 230 | assertf( lexpr, "Aggregate parameters should be type expressions" ); | 
|---|
|  | 231 | ast::TypeExpr const * rexpr = rparam->as<ast::TypeExpr>(); | 
|---|
|  | 232 | assertf( rexpr, "Aggregate parameters should be type expressions" ); | 
|---|
|  | 233 |  | 
|---|
|  | 234 | // xxx - might need to let VoidType be a wildcard here too; could have some voids | 
|---|
|  | 235 | // stuffed in for dtype-statics. | 
|---|
|  | 236 | // if ( is<VoidType>( lexpr->type() ) || is<VoidType>( bparam->get_type() ) ) continue; | 
|---|
|  | 237 | if ( !typesPolyCompatible( lexpr->type, rexpr->type ) ) { | 
|---|
| [3606fe4] | 238 | return false; | 
|---|
|  | 239 | } | 
|---|
|  | 240 | } | 
|---|
| [b8b5535] | 241 |  | 
|---|
|  | 242 | return true; | 
|---|
| [5a3ac84] | 243 | } | 
|---|
| [b8b5535] | 244 | } // namespace | 
|---|
| [5a3ac84] | 245 |  | 
|---|
| [f9ad69d] | 246 | // This function, and its helpers following, have logic duplicated from | 
|---|
|  | 247 | // unification.  The difference in context is that unification applies where | 
|---|
|  | 248 | // the types "must" match, while this variation applies to arbitrary type | 
|---|
|  | 249 | // pairs, when an optimization could apply if they happen to match.  This | 
|---|
|  | 250 | // variation does not bind type variables.  The helper functions support | 
|---|
|  | 251 | // the case for matching ArrayType. | 
|---|
|  | 252 | bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ); | 
|---|
|  | 253 |  | 
|---|
|  | 254 | static bool exprsPolyCompatibleByStaticValue( | 
|---|
|  | 255 | const ast::Expr * e1, const ast::Expr * e2 ) { | 
|---|
|  | 256 | Evaluation r1 = eval(e1); | 
|---|
|  | 257 | Evaluation r2 = eval(e2); | 
|---|
|  | 258 |  | 
|---|
|  | 259 | if ( !r1.hasKnownValue ) return false; | 
|---|
|  | 260 | if ( !r2.hasKnownValue ) return false; | 
|---|
|  | 261 |  | 
|---|
|  | 262 | if ( r1.knownValue != r2.knownValue ) return false; | 
|---|
|  | 263 |  | 
|---|
|  | 264 | return true; | 
|---|
|  | 265 | } | 
|---|
|  | 266 |  | 
|---|
|  | 267 | static bool exprsPolyCompatible( ast::Expr const * lhs, | 
|---|
|  | 268 | ast::Expr const * rhs ) { | 
|---|
|  | 269 | type_index const lid = typeid(*lhs); | 
|---|
|  | 270 | type_index const rid = typeid(*rhs); | 
|---|
|  | 271 | if ( lid != rid ) return false; | 
|---|
|  | 272 |  | 
|---|
|  | 273 | if ( exprsPolyCompatibleByStaticValue( lhs, rhs ) ) return true; | 
|---|
|  | 274 |  | 
|---|
|  | 275 | if ( type_index(typeid(ast::CastExpr)) == lid ) { | 
|---|
|  | 276 | ast::CastExpr const * l = as<ast::CastExpr>(lhs); | 
|---|
|  | 277 | ast::CastExpr const * r = as<ast::CastExpr>(rhs); | 
|---|
|  | 278 |  | 
|---|
|  | 279 | // inspect casts' target types | 
|---|
|  | 280 | if ( !typesPolyCompatible( | 
|---|
|  | 281 | l->result, r->result ) ) return false; | 
|---|
|  | 282 |  | 
|---|
|  | 283 | // inspect casts' inner expressions | 
|---|
|  | 284 | return exprsPolyCompatible( l->arg, r->arg ); | 
|---|
|  | 285 |  | 
|---|
|  | 286 | } else if ( type_index(typeid(ast::VariableExpr)) == lid ) { | 
|---|
|  | 287 | ast::VariableExpr const * l = as<ast::VariableExpr>(lhs); | 
|---|
|  | 288 | ast::VariableExpr const * r = as<ast::VariableExpr>(rhs); | 
|---|
|  | 289 |  | 
|---|
|  | 290 | assert(l->var); | 
|---|
|  | 291 | assert(r->var); | 
|---|
|  | 292 |  | 
|---|
|  | 293 | // conservative: variable exprs match if their declarations are | 
|---|
|  | 294 | // represented by the same C++ AST object | 
|---|
|  | 295 | return (l->var == r->var); | 
|---|
|  | 296 |  | 
|---|
|  | 297 | } else if ( type_index(typeid(ast::SizeofExpr)) == lid ) { | 
|---|
|  | 298 | ast::SizeofExpr const * l = as<ast::SizeofExpr>(lhs); | 
|---|
|  | 299 | ast::SizeofExpr const * r = as<ast::SizeofExpr>(rhs); | 
|---|
|  | 300 |  | 
|---|
| [b6f2e7ab] | 301 | assert( l->type ); | 
|---|
|  | 302 | assert( r->type ); | 
|---|
| [f9ad69d] | 303 |  | 
|---|
|  | 304 | // mutual recursion with type poly compatibility | 
|---|
|  | 305 | return typesPolyCompatible( l->type, r->type ); | 
|---|
|  | 306 |  | 
|---|
|  | 307 | } else { | 
|---|
|  | 308 | // All other forms compare on static value only, done earlier | 
|---|
|  | 309 | return false; | 
|---|
|  | 310 | } | 
|---|
|  | 311 | } | 
|---|
|  | 312 |  | 
|---|
| [3606fe4] | 313 | bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ) { | 
|---|
|  | 314 | type_index const lid = typeid(*lhs); | 
|---|
|  | 315 |  | 
|---|
|  | 316 | // Polymorphic types always match: | 
|---|
|  | 317 | if ( type_index(typeid(ast::TypeInstType)) == lid ) return true; | 
|---|
|  | 318 |  | 
|---|
|  | 319 | type_index const rid = typeid(*rhs); | 
|---|
|  | 320 | if ( type_index(typeid(ast::TypeInstType)) == rid ) return true; | 
|---|
|  | 321 |  | 
|---|
|  | 322 | // All other types only match if they are the same type: | 
|---|
|  | 323 | if ( lid != rid ) return false; | 
|---|
|  | 324 |  | 
|---|
|  | 325 | // So remaining types can be examined case by case. | 
|---|
| [f9ad69d] | 326 | // Recurse through type structure (conditions duplicated from Unify.cpp). | 
|---|
| [3606fe4] | 327 |  | 
|---|
|  | 328 | if ( type_index(typeid(ast::BasicType)) == lid ) { | 
|---|
|  | 329 | return as<ast::BasicType>(lhs)->kind == as<ast::BasicType>(rhs)->kind; | 
|---|
|  | 330 | } else if ( type_index(typeid(ast::PointerType)) == lid ) { | 
|---|
|  | 331 | ast::PointerType const * l = as<ast::PointerType>(lhs); | 
|---|
|  | 332 | ast::PointerType const * r = as<ast::PointerType>(rhs); | 
|---|
|  | 333 |  | 
|---|
|  | 334 | // void pointers should match any other pointer type. | 
|---|
|  | 335 | return is<ast::VoidType>( l->base.get() ) | 
|---|
|  | 336 | || is<ast::VoidType>( r->base.get() ) | 
|---|
|  | 337 | || typesPolyCompatible( l->base.get(), r->base.get() ); | 
|---|
|  | 338 | } else if ( type_index(typeid(ast::ReferenceType)) == lid ) { | 
|---|
|  | 339 | ast::ReferenceType const * l = as<ast::ReferenceType>(lhs); | 
|---|
|  | 340 | ast::ReferenceType const * r = as<ast::ReferenceType>(rhs); | 
|---|
|  | 341 |  | 
|---|
|  | 342 | // void references should match any other reference type. | 
|---|
|  | 343 | return is<ast::VoidType>( l->base.get() ) | 
|---|
|  | 344 | || is<ast::VoidType>( r->base.get() ) | 
|---|
|  | 345 | || typesPolyCompatible( l->base.get(), r->base.get() ); | 
|---|
|  | 346 | } else if ( type_index(typeid(ast::ArrayType)) == lid ) { | 
|---|
|  | 347 | ast::ArrayType const * l = as<ast::ArrayType>(lhs); | 
|---|
|  | 348 | ast::ArrayType const * r = as<ast::ArrayType>(rhs); | 
|---|
|  | 349 |  | 
|---|
| [f9ad69d] | 350 | if ( l->isVarLen != r->isVarLen ) return false; | 
|---|
|  | 351 | if ( (l->dimension != nullptr) != (r->dimension != nullptr) ) | 
|---|
|  | 352 | return false; | 
|---|
| [3606fe4] | 353 |  | 
|---|
| [f9ad69d] | 354 | if ( l->dimension ) { | 
|---|
|  | 355 | assert( r->dimension ); | 
|---|
|  | 356 | // mutual recursion with expression poly compatibility | 
|---|
|  | 357 | if ( !exprsPolyCompatible(l->dimension, r->dimension) ) | 
|---|
| [3606fe4] | 358 | return false; | 
|---|
|  | 359 | } | 
|---|
|  | 360 |  | 
|---|
|  | 361 | return typesPolyCompatible( l->base.get(), r->base.get() ); | 
|---|
|  | 362 | } else if ( type_index(typeid(ast::FunctionType)) == lid ) { | 
|---|
|  | 363 | ast::FunctionType const * l = as<ast::FunctionType>(lhs); | 
|---|
|  | 364 | ast::FunctionType const * r = as<ast::FunctionType>(rhs); | 
|---|
|  | 365 |  | 
|---|
|  | 366 | std::vector<ast::ptr<ast::Type>> lparams, rparams; | 
|---|
|  | 367 | flattenList( l->params, lparams ); | 
|---|
|  | 368 | flattenList( r->params, rparams ); | 
|---|
|  | 369 | if ( lparams.size() != rparams.size() ) return false; | 
|---|
|  | 370 | for ( unsigned i = 0; i < lparams.size(); ++i ) { | 
|---|
|  | 371 | if ( !typesPolyCompatible( lparams[i], rparams[i] ) ) return false; | 
|---|
|  | 372 | } | 
|---|
|  | 373 |  | 
|---|
|  | 374 | std::vector<ast::ptr<ast::Type>> lrets, rrets; | 
|---|
|  | 375 | flattenList( l->returns, lrets ); | 
|---|
|  | 376 | flattenList( r->returns, rrets ); | 
|---|
|  | 377 | if ( lrets.size() != rrets.size() ) return false; | 
|---|
|  | 378 | for ( unsigned i = 0; i < lrets.size(); ++i ) { | 
|---|
|  | 379 | if ( !typesPolyCompatible( lrets[i], rrets[i] ) ) return false; | 
|---|
|  | 380 | } | 
|---|
|  | 381 | return true; | 
|---|
|  | 382 | } else if ( type_index(typeid(ast::StructInstType)) == lid ) { | 
|---|
|  | 383 | ast::StructInstType const * l = as<ast::StructInstType>(lhs); | 
|---|
|  | 384 | ast::StructInstType const * r = as<ast::StructInstType>(rhs); | 
|---|
|  | 385 |  | 
|---|
|  | 386 | if ( l->name != r->name ) return false; | 
|---|
|  | 387 | return paramListsPolyCompatible( l->params, r->params ); | 
|---|
|  | 388 | } else if ( type_index(typeid(ast::UnionInstType)) == lid ) { | 
|---|
|  | 389 | ast::UnionInstType const * l = as<ast::UnionInstType>(lhs); | 
|---|
|  | 390 | ast::UnionInstType const * r = as<ast::UnionInstType>(rhs); | 
|---|
|  | 391 |  | 
|---|
|  | 392 | if ( l->name != r->name ) return false; | 
|---|
|  | 393 | return paramListsPolyCompatible( l->params, r->params ); | 
|---|
|  | 394 | } else if ( type_index(typeid(ast::EnumInstType)) == lid ) { | 
|---|
|  | 395 | ast::EnumInstType const * l = as<ast::EnumInstType>(lhs); | 
|---|
|  | 396 | ast::EnumInstType const * r = as<ast::EnumInstType>(rhs); | 
|---|
|  | 397 |  | 
|---|
|  | 398 | return l->name == r->name; | 
|---|
|  | 399 | } else if ( type_index(typeid(ast::TraitInstType)) == lid ) { | 
|---|
|  | 400 | ast::TraitInstType const * l = as<ast::TraitInstType>(lhs); | 
|---|
|  | 401 | ast::TraitInstType const * r = as<ast::TraitInstType>(rhs); | 
|---|
|  | 402 |  | 
|---|
|  | 403 | return l->name == r->name; | 
|---|
|  | 404 | } else if ( type_index(typeid(ast::TupleType)) == lid ) { | 
|---|
|  | 405 | ast::TupleType const * l = as<ast::TupleType>(lhs); | 
|---|
|  | 406 | ast::TupleType const * r = as<ast::TupleType>(rhs); | 
|---|
|  | 407 |  | 
|---|
|  | 408 | std::vector<ast::ptr<ast::Type>> ltypes, rtypes; | 
|---|
|  | 409 | flattenList( l->types, ( ltypes ) ); | 
|---|
|  | 410 | flattenList( r->types, ( rtypes ) ); | 
|---|
|  | 411 | if ( ltypes.size() != rtypes.size() ) return false; | 
|---|
|  | 412 |  | 
|---|
|  | 413 | for ( unsigned i = 0 ; i < ltypes.size() ; ++i ) { | 
|---|
|  | 414 | if ( !typesPolyCompatible( ltypes[i], rtypes[i] ) ) return false; | 
|---|
|  | 415 | } | 
|---|
|  | 416 | return true; | 
|---|
|  | 417 | // The remaining types (VoidType, VarArgsType, ZeroType & OneType) | 
|---|
|  | 418 | // have no variation so will always be equal. | 
|---|
|  | 419 | } else { | 
|---|
|  | 420 | return true; | 
|---|
|  | 421 | } | 
|---|
|  | 422 | } | 
|---|
|  | 423 |  | 
|---|
| [c8837e5] | 424 | bool needsBoxing( const ast::Type * param, const ast::Type * arg, | 
|---|
|  | 425 | const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { | 
|---|
|  | 426 | // Don't need to box if the parameter is not polymorphic. | 
|---|
|  | 427 | if ( !isPolyType( param, typeVars ) ) return false; | 
|---|
|  | 428 |  | 
|---|
|  | 429 | ast::ptr<ast::Type> newType = arg; | 
|---|
|  | 430 | if ( subst ) { | 
|---|
|  | 431 | int count = subst->apply( newType ); | 
|---|
|  | 432 | (void)count; | 
|---|
| [490fb92e] | 433 | } | 
|---|
| [c8837e5] | 434 | // Only need to box if the argument is not also polymorphic. | 
|---|
|  | 435 | return !isPolyType( newType ); | 
|---|
|  | 436 | } | 
|---|
| [490fb92e] | 437 |  | 
|---|
| [c8837e5] | 438 | bool needsBoxing( | 
|---|
|  | 439 | const ast::Type * param, const ast::Type * arg, | 
|---|
|  | 440 | const ast::ApplicationExpr * expr, | 
|---|
|  | 441 | const ast::TypeSubstitution * subst ) { | 
|---|
|  | 442 | const ast::FunctionType * function = getFunctionType( expr->func->result ); | 
|---|
| [b8b5535] | 443 | assertf( function, "ApplicationExpr has non-function type: %s", toCString( expr->func->result ) ); | 
|---|
| [52a5262e] | 444 | TypeVarMap exprTyVars; | 
|---|
| [c8837e5] | 445 | makeTypeVarMap( function, exprTyVars ); | 
|---|
|  | 446 | return needsBoxing( param, arg, exprTyVars, subst ); | 
|---|
|  | 447 | } | 
|---|
| [490fb92e] | 448 |  | 
|---|
| [c97b448] | 449 | void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) { | 
|---|
|  | 450 | typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) ); | 
|---|
|  | 451 | } | 
|---|
|  | 452 |  | 
|---|
| [c8837e5] | 453 | void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) { | 
|---|
| [c97b448] | 454 | typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) ); | 
|---|
| [c8837e5] | 455 | } | 
|---|
| [490fb92e] | 456 |  | 
|---|
| [c8837e5] | 457 | void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) { | 
|---|
|  | 458 | if ( auto func = dynamic_cast<ast::FunctionType const *>( type ) ) { | 
|---|
|  | 459 | for ( auto & typeVar : func->forall ) { | 
|---|
|  | 460 | assert( typeVar ); | 
|---|
|  | 461 | addToTypeVarMap( typeVar, typeVars ); | 
|---|
| [490fb92e] | 462 | } | 
|---|
|  | 463 | } | 
|---|
| [c8837e5] | 464 | if ( auto pointer = dynamic_cast<ast::PointerType const *>( type ) ) { | 
|---|
|  | 465 | makeTypeVarMap( pointer->base, typeVars ); | 
|---|
|  | 466 | } | 
|---|
|  | 467 | } | 
|---|
| [490fb92e] | 468 |  | 
|---|
| [c97b448] | 469 | void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ) { | 
|---|
|  | 470 | for ( auto & typeDecl : decl->type_params ) { | 
|---|
|  | 471 | addToTypeVarMap( typeDecl, typeVars ); | 
|---|
|  | 472 | } | 
|---|
|  | 473 | } | 
|---|
|  | 474 |  | 
|---|
| [51b73452] | 475 | } // namespace GenPoly | 
|---|
| [01aeade] | 476 |  | 
|---|
| [51587aa] | 477 | // Local Variables: // | 
|---|
|  | 478 | // tab-width: 4 // | 
|---|
|  | 479 | // mode: c++ // | 
|---|
|  | 480 | // compile-command: "make install" // | 
|---|
|  | 481 | // End: // | 
|---|