| [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 | // | 
|---|
| [540de412] | 7 | // GenPoly.cc -- | 
|---|
| [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 |  | 
|---|
|  | 16 | #include "GenPoly.h" | 
|---|
| [ffad73a] | 17 |  | 
|---|
| [08fc48f] | 18 | #include <cassert>                      // for assertf, assert | 
|---|
|  | 19 | #include <iostream>                     // for operator<<, ostream, basic_os... | 
|---|
|  | 20 | #include <iterator>                     // for back_insert_iterator, back_in... | 
|---|
|  | 21 | #include <list>                         // for list, _List_iterator, list<>:... | 
|---|
|  | 22 | #include <typeindex>                    // for type_index | 
|---|
|  | 23 | #include <utility>                      // for pair | 
|---|
|  | 24 | #include <vector>                       // for vector | 
|---|
|  | 25 |  | 
|---|
| [a0d1f1c] | 26 | #include "AST/Expr.hpp" | 
|---|
| [d76c588] | 27 | #include "AST/Type.hpp" | 
|---|
| [a0d1f1c] | 28 | #include "AST/TypeSubstitution.hpp" | 
|---|
| [08fc48f] | 29 | #include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::const_it... | 
|---|
|  | 30 | #include "ResolvExpr/typeops.h"         // for flatten | 
|---|
|  | 31 | #include "SynTree/Constant.h"           // for Constant | 
|---|
|  | 32 | #include "SynTree/Expression.h"         // for Expression, TypeExpr, Constan... | 
|---|
|  | 33 | #include "SynTree/Type.h"               // for Type, StructInstType, UnionIn... | 
|---|
|  | 34 | #include "SynTree/TypeSubstitution.h"   // for TypeSubstitution | 
|---|
| [51b73452] | 35 |  | 
|---|
| [b1a6d6b] | 36 | using namespace std; | 
|---|
| [51b73452] | 37 |  | 
|---|
|  | 38 | namespace GenPoly { | 
|---|
| [ffad73a] | 39 | namespace { | 
|---|
| [0f889a77] | 40 | /// Checks a parameter list for polymorphic parameters; will substitute according to env if present | 
|---|
|  | 41 | bool hasPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) { | 
|---|
|  | 42 | for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { | 
|---|
|  | 43 | TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); | 
|---|
| [7350ff97] | 44 | assertf(paramType, "Aggregate parameters should be type expressions"); | 
|---|
| [0f889a77] | 45 | if ( isPolyType( paramType->get_type(), env ) ) return true; | 
|---|
|  | 46 | } | 
|---|
|  | 47 | return false; | 
|---|
|  | 48 | } | 
|---|
|  | 49 |  | 
|---|
| [490fb92e] | 50 | bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) { | 
|---|
|  | 51 | for (auto ¶m : params) { | 
|---|
|  | 52 | auto paramType = param.strict_as<ast::TypeExpr>(); | 
|---|
|  | 53 | if (isPolyType(paramType->type, env)) return true; | 
|---|
|  | 54 | } | 
|---|
|  | 55 | return false; | 
|---|
|  | 56 | } | 
|---|
|  | 57 |  | 
|---|
| [0f889a77] | 58 | /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present | 
|---|
| [ffad73a] | 59 | bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { | 
|---|
|  | 60 | for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { | 
|---|
|  | 61 | TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); | 
|---|
| [5a3ac84] | 62 | assertf(paramType, "Aggregate parameters should be type expressions"); | 
|---|
| [ffad73a] | 63 | if ( isPolyType( paramType->get_type(), tyVars, env ) ) return true; | 
|---|
|  | 64 | } | 
|---|
|  | 65 | return false; | 
|---|
|  | 66 | } | 
|---|
| [3bb195cb] | 67 |  | 
|---|
|  | 68 | /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present | 
|---|
|  | 69 | bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { | 
|---|
|  | 70 | for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { | 
|---|
|  | 71 | TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); | 
|---|
| [5a3ac84] | 72 | assertf(paramType, "Aggregate parameters should be type expressions"); | 
|---|
| [3bb195cb] | 73 | if ( isDynType( paramType->get_type(), tyVars, env ) ) return true; | 
|---|
|  | 74 | } | 
|---|
|  | 75 | return false; | 
|---|
|  | 76 | } | 
|---|
| [5a3ac84] | 77 |  | 
|---|
| [c8837e5] | 78 | bool hasDynParams( | 
|---|
|  | 79 | const std::vector<ast::ptr<ast::Expr>> & params, | 
|---|
|  | 80 | const TypeVarMap & typeVars, | 
|---|
|  | 81 | const ast::TypeSubstitution * subst ) { | 
|---|
|  | 82 | for ( ast::ptr<ast::Expr> const & paramExpr : params ) { | 
|---|
|  | 83 | auto param = paramExpr.as<ast::TypeExpr>(); | 
|---|
|  | 84 | assertf( param, "Aggregate parameters should be type expressions." ); | 
|---|
|  | 85 | if ( isDynType( param->type.get(), typeVars, subst ) ) { | 
|---|
| [3606fe4] | 86 | return true; | 
|---|
|  | 87 | } | 
|---|
|  | 88 | } | 
|---|
|  | 89 | return false; | 
|---|
|  | 90 | } | 
|---|
|  | 91 |  | 
|---|
| [5a3ac84] | 92 | /// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present | 
|---|
|  | 93 | bool includesPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) { | 
|---|
|  | 94 | for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { | 
|---|
|  | 95 | TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); | 
|---|
|  | 96 | assertf(paramType, "Aggregate parameters should be type expressions"); | 
|---|
|  | 97 | if ( includesPolyType( paramType->get_type(), env ) ) return true; | 
|---|
|  | 98 | } | 
|---|
|  | 99 | return false; | 
|---|
|  | 100 | } | 
|---|
|  | 101 |  | 
|---|
|  | 102 | /// Checks a parameter list for inclusion of polymorphic parameters from tyVars; will substitute according to env if present | 
|---|
|  | 103 | bool includesPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { | 
|---|
|  | 104 | for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { | 
|---|
|  | 105 | TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); | 
|---|
|  | 106 | assertf(paramType, "Aggregate parameters should be type expressions"); | 
|---|
|  | 107 | if ( includesPolyType( paramType->get_type(), tyVars, env ) ) return true; | 
|---|
|  | 108 | } | 
|---|
|  | 109 | return false; | 
|---|
|  | 110 | } | 
|---|
| [c2ad3c9] | 111 | } | 
|---|
| [83de11e] | 112 |  | 
|---|
| [c2ad3c9] | 113 | Type* replaceTypeInst( Type* type, const TypeSubstitution* env ) { | 
|---|
|  | 114 | if ( ! env ) return type; | 
|---|
|  | 115 | if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) { | 
|---|
|  | 116 | Type *newType = env->lookup( typeInst->get_name() ); | 
|---|
|  | 117 | if ( newType ) return newType; | 
|---|
| [e24955a] | 118 | } | 
|---|
| [c2ad3c9] | 119 | return type; | 
|---|
| [ffad73a] | 120 | } | 
|---|
| [0f889a77] | 121 |  | 
|---|
| [4da152a] | 122 | const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) { | 
|---|
|  | 123 | if ( ! env ) return type; | 
|---|
|  | 124 | if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) { | 
|---|
|  | 125 | Type *newType = env->lookup( typeInst->get_name() ); | 
|---|
|  | 126 | if ( newType ) return newType; | 
|---|
|  | 127 | } | 
|---|
|  | 128 | return type; | 
|---|
|  | 129 | } | 
|---|
|  | 130 |  | 
|---|
| [490fb92e] | 131 | const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) { | 
|---|
|  | 132 | if (!env) return type; | 
|---|
| [75f6a5f] | 133 | if ( auto typeInst = dynamic_cast<const ast::TypeInstType*>(type) ) { | 
|---|
| [3e5dd913] | 134 | auto newType = env->lookup(typeInst); | 
|---|
| [490fb92e] | 135 | if (newType) return newType; | 
|---|
|  | 136 | } | 
|---|
|  | 137 | return type; | 
|---|
|  | 138 | } | 
|---|
|  | 139 |  | 
|---|
| [0f889a77] | 140 | Type *isPolyType( Type *type, const TypeSubstitution *env ) { | 
|---|
| [e24955a] | 141 | type = replaceTypeInst( type, env ); | 
|---|
| [83de11e] | 142 |  | 
|---|
| [ca35c51] | 143 | if ( dynamic_cast< TypeInstType * >( type ) ) { | 
|---|
| [0f889a77] | 144 | return type; | 
|---|
| [5f61546] | 145 | } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { | 
|---|
|  | 146 | return isPolyType( arrayType->base, env ); | 
|---|
| [0f889a77] | 147 | } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { | 
|---|
|  | 148 | if ( hasPolyParams( structType->get_parameters(), env ) ) return type; | 
|---|
|  | 149 | } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { | 
|---|
|  | 150 | if ( hasPolyParams( unionType->get_parameters(), env ) ) return type; | 
|---|
|  | 151 | } | 
|---|
|  | 152 | return 0; | 
|---|
|  | 153 | } | 
|---|
| [540de412] | 154 |  | 
|---|
| [490fb92e] | 155 | const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env) { | 
|---|
|  | 156 | type = replaceTypeInst( type, env ); | 
|---|
|  | 157 |  | 
|---|
|  | 158 | if ( dynamic_cast< const ast::TypeInstType * >( type ) ) { | 
|---|
|  | 159 | return type; | 
|---|
|  | 160 | } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { | 
|---|
|  | 161 | return isPolyType( arrayType->base, env ); | 
|---|
|  | 162 | } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { | 
|---|
|  | 163 | if ( hasPolyParams( structType->params, env ) ) return type; | 
|---|
|  | 164 | } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { | 
|---|
|  | 165 | if ( hasPolyParams( unionType->params, env ) ) return type; | 
|---|
|  | 166 | } | 
|---|
|  | 167 | return 0; | 
|---|
|  | 168 | } | 
|---|
|  | 169 |  | 
|---|
| [ffad73a] | 170 | Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { | 
|---|
| [e24955a] | 171 | type = replaceTypeInst( type, env ); | 
|---|
| [83de11e] | 172 |  | 
|---|
| [e56cfdb0] | 173 | if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) { | 
|---|
| [e9b5043] | 174 | if ( tyVars.contains( typeInst->get_name() ) ) { | 
|---|
| [ffad73a] | 175 | return type; | 
|---|
| [0f889a77] | 176 | } | 
|---|
| [5f61546] | 177 | } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { | 
|---|
|  | 178 | return isPolyType( arrayType->base, tyVars, env ); | 
|---|
| [ffad73a] | 179 | } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { | 
|---|
|  | 180 | if ( hasPolyParams( structType->get_parameters(), tyVars, env ) ) return type; | 
|---|
|  | 181 | } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { | 
|---|
|  | 182 | if ( hasPolyParams( unionType->get_parameters(), tyVars, env ) ) return type; | 
|---|
|  | 183 | } | 
|---|
|  | 184 | return 0; | 
|---|
| [01aeade] | 185 | } | 
|---|
| [b1a6d6b] | 186 |  | 
|---|
| [490fb92e] | 187 | const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env) { | 
|---|
|  | 188 | type = replaceTypeInst( type, env ); | 
|---|
|  | 189 |  | 
|---|
|  | 190 | if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) { | 
|---|
| [e9b5043] | 191 | if ( tyVars.contains( typeInst->typeString() ) ) return type; | 
|---|
| [490fb92e] | 192 | } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { | 
|---|
|  | 193 | return isPolyType( arrayType->base, env ); | 
|---|
|  | 194 | } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { | 
|---|
|  | 195 | if ( hasPolyParams( structType->params, env ) ) return type; | 
|---|
|  | 196 | } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { | 
|---|
|  | 197 | if ( hasPolyParams( unionType->params, env ) ) return type; | 
|---|
|  | 198 | } | 
|---|
|  | 199 | return nullptr; | 
|---|
|  | 200 | } | 
|---|
|  | 201 |  | 
|---|
| [c8837e5] | 202 | const ast::Type * isPolyType( const ast::Type * type, | 
|---|
|  | 203 | const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { | 
|---|
|  | 204 | type = replaceTypeInst( type, subst ); | 
|---|
|  | 205 |  | 
|---|
|  | 206 | if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { | 
|---|
| [e9b5043] | 207 | if ( typeVars.contains( *inst ) ) return type; | 
|---|
| [c8837e5] | 208 | } else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) { | 
|---|
|  | 209 | return isPolyType( array->base, subst ); | 
|---|
|  | 210 | } else if ( auto sue = dynamic_cast< const ast::StructInstType * >( type ) ) { | 
|---|
|  | 211 | if ( hasPolyParams( sue->params, subst ) ) return type; | 
|---|
|  | 212 | } else if ( auto sue = dynamic_cast< const ast::UnionInstType * >( type ) ) { | 
|---|
|  | 213 | if ( hasPolyParams( sue->params, subst ) ) return type; | 
|---|
|  | 214 | } | 
|---|
|  | 215 | return nullptr; | 
|---|
|  | 216 | } | 
|---|
|  | 217 |  | 
|---|
| [33a7b6d] | 218 | ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { | 
|---|
| [3bb195cb] | 219 | type = replaceTypeInst( type, env ); | 
|---|
|  | 220 |  | 
|---|
|  | 221 | if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) { | 
|---|
|  | 222 | auto var = tyVars.find( typeInst->get_name() ); | 
|---|
| [2c57025] | 223 | if ( var != tyVars.end() && var->second.isComplete ) { | 
|---|
| [33a7b6d] | 224 | return typeInst; | 
|---|
| [3bb195cb] | 225 | } | 
|---|
|  | 226 | } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { | 
|---|
| [33a7b6d] | 227 | if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return structType; | 
|---|
| [3bb195cb] | 228 | } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { | 
|---|
| [33a7b6d] | 229 | if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return unionType; | 
|---|
| [3bb195cb] | 230 | } | 
|---|
|  | 231 | return 0; | 
|---|
|  | 232 | } | 
|---|
|  | 233 |  | 
|---|
| [c8837e5] | 234 | const ast::BaseInstType * isDynType( | 
|---|
|  | 235 | const ast::Type * type, const TypeVarMap & typeVars, | 
|---|
|  | 236 | const ast::TypeSubstitution * subst ) { | 
|---|
|  | 237 | type = replaceTypeInst( type, subst ); | 
|---|
|  | 238 |  | 
|---|
|  | 239 | if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) { | 
|---|
| [63d1ebe] | 240 | auto var = typeVars.find( *inst ); | 
|---|
| [c8837e5] | 241 | if ( var != typeVars.end() && var->second.isComplete ) { | 
|---|
| [75f6a5f] | 242 | return inst; | 
|---|
| [3606fe4] | 243 | } | 
|---|
| [c8837e5] | 244 | } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) { | 
|---|
|  | 245 | if ( hasDynParams( inst->params, typeVars, subst ) ) { | 
|---|
|  | 246 | return inst; | 
|---|
|  | 247 | } | 
|---|
|  | 248 | } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) { | 
|---|
|  | 249 | if ( hasDynParams( inst->params, typeVars, subst ) ) { | 
|---|
|  | 250 | return inst; | 
|---|
|  | 251 | } | 
|---|
| [3606fe4] | 252 | } | 
|---|
| [c8837e5] | 253 | return nullptr; | 
|---|
|  | 254 | } | 
|---|
| [3606fe4] | 255 |  | 
|---|
| [3bb195cb] | 256 | ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) { | 
|---|
|  | 257 | if ( function->get_returnVals().empty() ) return 0; | 
|---|
| [8c49c0e] | 258 |  | 
|---|
| [3bb195cb] | 259 | return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes ); | 
|---|
|  | 260 | } | 
|---|
|  | 261 |  | 
|---|
| [c8837e5] | 262 | const ast::BaseInstType *isDynRet( | 
|---|
|  | 263 | const ast::FunctionType * type, const TypeVarMap & typeVars ) { | 
|---|
|  | 264 | if ( type->returns.empty() ) return nullptr; | 
|---|
|  | 265 |  | 
|---|
|  | 266 | return isDynType( type->returns.front(), typeVars ); | 
|---|
|  | 267 | } | 
|---|
|  | 268 |  | 
|---|
| [3bb195cb] | 269 | ReferenceToType *isDynRet( FunctionType *function ) { | 
|---|
|  | 270 | if ( function->get_returnVals().empty() ) return 0; | 
|---|
|  | 271 |  | 
|---|
| [2c57025] | 272 | TyVarMap forallTypes( TypeDecl::Data{} ); | 
|---|
| [3bb195cb] | 273 | makeTyVarMap( function, forallTypes ); | 
|---|
|  | 274 | return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes ); | 
|---|
|  | 275 | } | 
|---|
|  | 276 |  | 
|---|
| [c97b448] | 277 | const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) { | 
|---|
|  | 278 | if ( func->returns.empty() ) return nullptr; | 
|---|
|  | 279 |  | 
|---|
|  | 280 | TypeVarMap forallTypes = { ast::TypeData() }; | 
|---|
|  | 281 | makeTypeVarMap( func, forallTypes ); | 
|---|
|  | 282 | return isDynType( func->returns.front(), forallTypes ); | 
|---|
|  | 283 | } | 
|---|
|  | 284 |  | 
|---|
| [3bb195cb] | 285 | bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) { | 
|---|
|  | 286 | //              if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) { | 
|---|
|  | 287 | //                      return true; | 
|---|
|  | 288 | //              } // if | 
|---|
|  | 289 | if ( isDynRet( adaptee, tyVars ) ) return true; | 
|---|
| [8c49c0e] | 290 |  | 
|---|
| [3bb195cb] | 291 | for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) { | 
|---|
|  | 292 | //                      if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) { | 
|---|
|  | 293 | if ( isDynType( (*innerArg)->get_type(), tyVars ) ) { | 
|---|
|  | 294 | return true; | 
|---|
|  | 295 | } // if | 
|---|
|  | 296 | } // for | 
|---|
|  | 297 | return false; | 
|---|
|  | 298 | } | 
|---|
|  | 299 |  | 
|---|
| [c8837e5] | 300 | bool needsAdapter( | 
|---|
|  | 301 | ast::FunctionType const * adaptee, const TypeVarMap & typeVars ) { | 
|---|
|  | 302 | if ( isDynRet( adaptee, typeVars ) ) return true; | 
|---|
|  | 303 |  | 
|---|
|  | 304 | for ( auto param : adaptee->params ) { | 
|---|
|  | 305 | if ( isDynType( param, typeVars ) ) { | 
|---|
|  | 306 | return true; | 
|---|
|  | 307 | } | 
|---|
|  | 308 | } | 
|---|
|  | 309 | return false; | 
|---|
|  | 310 | } | 
|---|
|  | 311 |  | 
|---|
| [0f889a77] | 312 | Type *isPolyPtr( Type *type, const TypeSubstitution *env ) { | 
|---|
| [e24955a] | 313 | type = replaceTypeInst( type, env ); | 
|---|
| [83de11e] | 314 |  | 
|---|
| [0f889a77] | 315 | if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) { | 
|---|
|  | 316 | return isPolyType( ptr->get_base(), env ); | 
|---|
| [e24955a] | 317 | } | 
|---|
| [0f889a77] | 318 | return 0; | 
|---|
|  | 319 | } | 
|---|
| [540de412] | 320 |  | 
|---|
| [ffad73a] | 321 | Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { | 
|---|
| [e24955a] | 322 | type = replaceTypeInst( type, env ); | 
|---|
| [83de11e] | 323 |  | 
|---|
| [ffad73a] | 324 | if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) { | 
|---|
|  | 325 | return isPolyType( ptr->get_base(), tyVars, env ); | 
|---|
| [e24955a] | 326 | } | 
|---|
| [ffad73a] | 327 | return 0; | 
|---|
| [bdf1954] | 328 | } | 
|---|
|  | 329 |  | 
|---|
| [c97b448] | 330 | const ast::Type * isPolyPtr( | 
|---|
|  | 331 | const ast::Type * type, const TypeVarMap & typeVars, | 
|---|
|  | 332 | const ast::TypeSubstitution * typeSubs ) { | 
|---|
|  | 333 | type = replaceTypeInst( type, typeSubs ); | 
|---|
|  | 334 |  | 
|---|
|  | 335 | if ( auto * ptr = dynamic_cast<ast::PointerType const *>( type ) ) { | 
|---|
|  | 336 | return isPolyType( ptr->base, typeVars, typeSubs ); | 
|---|
|  | 337 | } | 
|---|
|  | 338 | return nullptr; | 
|---|
|  | 339 | } | 
|---|
|  | 340 |  | 
|---|
| [8488c715] | 341 | Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) { | 
|---|
|  | 342 | int dummy; | 
|---|
|  | 343 | if ( ! levels ) { levels = &dummy; } | 
|---|
|  | 344 | *levels = 0; | 
|---|
|  | 345 |  | 
|---|
|  | 346 | while ( true ) { | 
|---|
| [e24955a] | 347 | type = replaceTypeInst( type, env ); | 
|---|
| [83de11e] | 348 |  | 
|---|
| [8488c715] | 349 | if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) { | 
|---|
|  | 350 | type = ptr->get_base(); | 
|---|
|  | 351 | ++(*levels); | 
|---|
|  | 352 | } else break; | 
|---|
| [05d47278] | 353 | } | 
|---|
|  | 354 |  | 
|---|
|  | 355 | return isPolyType( type, env ); | 
|---|
|  | 356 | } | 
|---|
| [540de412] | 357 |  | 
|---|
| [8488c715] | 358 | Type * hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels, const TypeSubstitution *env ) { | 
|---|
|  | 359 | int dummy; | 
|---|
|  | 360 | if ( ! levels ) { levels = &dummy; } | 
|---|
|  | 361 | *levels = 0; | 
|---|
|  | 362 |  | 
|---|
|  | 363 | while ( true ) { | 
|---|
| [e24955a] | 364 | type = replaceTypeInst( type, env ); | 
|---|
| [83de11e] | 365 |  | 
|---|
| [8488c715] | 366 | if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) { | 
|---|
|  | 367 | type = ptr->get_base(); | 
|---|
|  | 368 | ++(*levels); | 
|---|
|  | 369 | } else break; | 
|---|
| [05d47278] | 370 | } | 
|---|
|  | 371 |  | 
|---|
|  | 372 | return isPolyType( type, tyVars, env ); | 
|---|
|  | 373 | } | 
|---|
|  | 374 |  | 
|---|
| [c8837e5] | 375 | ast::Type const * hasPolyBase( | 
|---|
|  | 376 | ast::Type const * type, const TypeVarMap & typeVars, | 
|---|
|  | 377 | int * levels, const ast::TypeSubstitution * subst ) { | 
|---|
|  | 378 | int level_count = 0; | 
|---|
|  | 379 |  | 
|---|
|  | 380 | while ( true ) { | 
|---|
|  | 381 | type = replaceTypeInst( type, subst ); | 
|---|
|  | 382 |  | 
|---|
|  | 383 | if ( auto ptr = dynamic_cast<ast::PointerType const *>( type ) ) { | 
|---|
|  | 384 | type = ptr->base; | 
|---|
|  | 385 | ++level_count; | 
|---|
|  | 386 | } else { | 
|---|
|  | 387 | break; | 
|---|
|  | 388 | } | 
|---|
|  | 389 | } | 
|---|
|  | 390 |  | 
|---|
|  | 391 | if ( nullptr != levels ) { *levels = level_count; } | 
|---|
|  | 392 | return isPolyType( type, typeVars, subst ); | 
|---|
|  | 393 | } | 
|---|
|  | 394 |  | 
|---|
| [5a3ac84] | 395 | bool includesPolyType( Type *type, const TypeSubstitution *env ) { | 
|---|
|  | 396 | type = replaceTypeInst( type, env ); | 
|---|
|  | 397 |  | 
|---|
|  | 398 | if ( dynamic_cast< TypeInstType * >( type ) ) { | 
|---|
|  | 399 | return true; | 
|---|
|  | 400 | } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) { | 
|---|
|  | 401 | if ( includesPolyType( pointerType->get_base(), env ) ) return true; | 
|---|
|  | 402 | } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { | 
|---|
|  | 403 | if ( includesPolyParams( structType->get_parameters(), env ) ) return true; | 
|---|
|  | 404 | } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { | 
|---|
|  | 405 | if ( includesPolyParams( unionType->get_parameters(), env ) ) return true; | 
|---|
|  | 406 | } | 
|---|
|  | 407 | return false; | 
|---|
|  | 408 | } | 
|---|
|  | 409 |  | 
|---|
|  | 410 | bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { | 
|---|
|  | 411 | type = replaceTypeInst( type, env ); | 
|---|
|  | 412 |  | 
|---|
|  | 413 | if ( TypeInstType *typeInstType = dynamic_cast< TypeInstType * >( type ) ) { | 
|---|
| [e9b5043] | 414 | if ( tyVars.contains( typeInstType->get_name() ) ) { | 
|---|
| [5a3ac84] | 415 | return true; | 
|---|
|  | 416 | } | 
|---|
|  | 417 | } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) { | 
|---|
|  | 418 | if ( includesPolyType( pointerType->get_base(), tyVars, env ) ) return true; | 
|---|
|  | 419 | } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { | 
|---|
|  | 420 | if ( includesPolyParams( structType->get_parameters(), tyVars, env ) ) return true; | 
|---|
|  | 421 | } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { | 
|---|
|  | 422 | if ( includesPolyParams( unionType->get_parameters(), tyVars, env ) ) return true; | 
|---|
|  | 423 | } | 
|---|
|  | 424 | return false; | 
|---|
|  | 425 | } | 
|---|
|  | 426 |  | 
|---|
| [7754cde] | 427 | FunctionType * getFunctionType( Type *ty ) { | 
|---|
|  | 428 | PointerType *ptrType; | 
|---|
|  | 429 | if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) { | 
|---|
|  | 430 | return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise | 
|---|
|  | 431 | } else { | 
|---|
|  | 432 | return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise | 
|---|
|  | 433 | } | 
|---|
|  | 434 | } | 
|---|
|  | 435 |  | 
|---|
| [d76c588] | 436 | const ast::FunctionType * getFunctionType( const ast::Type * ty ) { | 
|---|
|  | 437 | if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) { | 
|---|
|  | 438 | return pty->base.as< ast::FunctionType >(); | 
|---|
|  | 439 | } else { | 
|---|
|  | 440 | return dynamic_cast< const ast::FunctionType * >( ty ); | 
|---|
|  | 441 | } | 
|---|
|  | 442 | } | 
|---|
|  | 443 |  | 
|---|
| [8488c715] | 444 | VariableExpr * getBaseVar( Expression *expr, int *levels ) { | 
|---|
|  | 445 | int dummy; | 
|---|
|  | 446 | if ( ! levels ) { levels = &dummy; } | 
|---|
|  | 447 | *levels = 0; | 
|---|
|  | 448 |  | 
|---|
|  | 449 | while ( true ) { | 
|---|
|  | 450 | if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) { | 
|---|
|  | 451 | return varExpr; | 
|---|
| [d9f1b2d] | 452 | } else if ( MemberExpr *memberExpr = dynamic_cast< MemberExpr* >( expr ) ) { | 
|---|
|  | 453 | expr = memberExpr->get_aggregate(); | 
|---|
| [8488c715] | 454 | } else if ( AddressExpr *addressExpr = dynamic_cast< AddressExpr* >( expr ) ) { | 
|---|
|  | 455 | expr = addressExpr->get_arg(); | 
|---|
|  | 456 | } else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) { | 
|---|
|  | 457 | // look for compiler-inserted dereference operator | 
|---|
|  | 458 | NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() ); | 
|---|
|  | 459 | if ( ! fn || fn->get_name() != std::string("*?") ) return 0; | 
|---|
|  | 460 | expr = *untypedExpr->begin_args(); | 
|---|
| [540de412] | 461 | } else if ( CommaExpr *commaExpr = dynamic_cast< CommaExpr* >( expr ) ) { | 
|---|
|  | 462 | // copy constructors insert comma exprs, look at second argument which contains the variable | 
|---|
|  | 463 | expr = commaExpr->get_arg2(); | 
|---|
|  | 464 | continue; | 
|---|
| [1aa4b71] | 465 | } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( expr ) ) { | 
|---|
|  | 466 | int lvl1; | 
|---|
|  | 467 | int lvl2; | 
|---|
|  | 468 | VariableExpr * var1 = getBaseVar( condExpr->get_arg2(), &lvl1 ); | 
|---|
|  | 469 | VariableExpr * var2 = getBaseVar( condExpr->get_arg3(), &lvl2 ); | 
|---|
|  | 470 | if ( lvl1 == lvl2 && var1 && var2 && var1->get_var() == var2->get_var() ) { | 
|---|
|  | 471 | *levels = lvl1; | 
|---|
|  | 472 | return var1; | 
|---|
|  | 473 | } | 
|---|
|  | 474 | break; | 
|---|
| [8488c715] | 475 | } else break; | 
|---|
|  | 476 |  | 
|---|
|  | 477 | ++(*levels); | 
|---|
|  | 478 | } | 
|---|
|  | 479 |  | 
|---|
|  | 480 | return 0; | 
|---|
| [05d47278] | 481 | } | 
|---|
|  | 482 |  | 
|---|
| [5a3ac84] | 483 | namespace { | 
|---|
|  | 484 | /// Checks if is a pointer to D | 
|---|
|  | 485 | template<typename D, typename B> | 
|---|
|  | 486 | bool is( const B* p ) { return type_index{typeid(D)} == type_index{typeid(*p)}; } | 
|---|
|  | 487 |  | 
|---|
|  | 488 | /// Converts to a pointer to D without checking for safety | 
|---|
|  | 489 | template<typename D, typename B> | 
|---|
|  | 490 | inline D* as( B* p ) { return reinterpret_cast<D*>(p); } | 
|---|
|  | 491 |  | 
|---|
| [3606fe4] | 492 | template<typename D, typename B> | 
|---|
|  | 493 | inline D const * as( B const * p ) { | 
|---|
|  | 494 | return reinterpret_cast<D const *>( p ); | 
|---|
|  | 495 | } | 
|---|
|  | 496 |  | 
|---|
| [5a3ac84] | 497 | /// Flattens a declaration list | 
|---|
|  | 498 | template<typename Output> | 
|---|
|  | 499 | void flattenList( list< DeclarationWithType* > src, Output out ) { | 
|---|
|  | 500 | for ( DeclarationWithType* decl : src ) { | 
|---|
|  | 501 | ResolvExpr::flatten( decl->get_type(), out ); | 
|---|
|  | 502 | } | 
|---|
|  | 503 | } | 
|---|
|  | 504 |  | 
|---|
|  | 505 | /// Flattens a list of types | 
|---|
|  | 506 | template<typename Output> | 
|---|
|  | 507 | void flattenList( list< Type* > src, Output out ) { | 
|---|
|  | 508 | for ( Type* ty : src ) { | 
|---|
|  | 509 | ResolvExpr::flatten( ty, out ); | 
|---|
|  | 510 | } | 
|---|
|  | 511 | } | 
|---|
|  | 512 |  | 
|---|
| [7b5694d] | 513 | /// Flattens a list of types. | 
|---|
|  | 514 | // There is another flattenList in Unify. | 
|---|
| [3606fe4] | 515 | void flattenList( vector<ast::ptr<ast::Type>> const & src, | 
|---|
|  | 516 | vector<ast::ptr<ast::Type>> & out ) { | 
|---|
|  | 517 | for ( auto const & type : src ) { | 
|---|
|  | 518 | ResolvExpr::flatten( type, out ); | 
|---|
|  | 519 | } | 
|---|
|  | 520 | } | 
|---|
|  | 521 |  | 
|---|
| [5a3ac84] | 522 | /// Checks if two lists of parameters are equal up to polymorphic substitution. | 
|---|
|  | 523 | bool paramListsPolyCompatible( const list< Expression* >& aparams, const list< Expression* >& bparams ) { | 
|---|
|  | 524 | if ( aparams.size() != bparams.size() ) return false; | 
|---|
|  | 525 |  | 
|---|
|  | 526 | for ( list< Expression* >::const_iterator at = aparams.begin(), bt = bparams.begin(); | 
|---|
|  | 527 | at != aparams.end(); ++at, ++bt ) { | 
|---|
|  | 528 | TypeExpr *aparam = dynamic_cast< TypeExpr* >(*at); | 
|---|
|  | 529 | assertf(aparam, "Aggregate parameters should be type expressions"); | 
|---|
|  | 530 | TypeExpr *bparam = dynamic_cast< TypeExpr* >(*bt); | 
|---|
|  | 531 | assertf(bparam, "Aggregate parameters should be type expressions"); | 
|---|
|  | 532 |  | 
|---|
| [cccc534] | 533 | // xxx - might need to let VoidType be a wildcard here too; could have some voids | 
|---|
| [5a3ac84] | 534 | // stuffed in for dtype-statics. | 
|---|
|  | 535 | // if ( is<VoidType>( aparam->get_type() ) || is<VoidType>( bparam->get_type() ) ) continue; | 
|---|
|  | 536 | if ( ! typesPolyCompatible( aparam->get_type(), bparam->get_type() ) ) return false; | 
|---|
|  | 537 | } | 
|---|
| [cccc534] | 538 |  | 
|---|
| [5a3ac84] | 539 | return true; | 
|---|
|  | 540 | } | 
|---|
| [3606fe4] | 541 |  | 
|---|
|  | 542 | bool paramListsPolyCompatible( | 
|---|
|  | 543 | std::vector<ast::ptr<ast::Expr>> const & lparams, | 
|---|
|  | 544 | std::vector<ast::ptr<ast::Expr>> const & rparams ) { | 
|---|
|  | 545 | if ( lparams.size() != rparams.size() ) { | 
|---|
|  | 546 | return false; | 
|---|
|  | 547 | } | 
|---|
|  | 548 |  | 
|---|
|  | 549 | for ( auto lparam = lparams.begin(), rparam = rparams.begin() ; | 
|---|
|  | 550 | lparam != lparams.end() ; ++lparam, ++rparam ) { | 
|---|
|  | 551 | ast::TypeExpr const * lexpr = lparam->as<ast::TypeExpr>(); | 
|---|
|  | 552 | assertf( lexpr, "Aggregate parameters should be type expressions" ); | 
|---|
|  | 553 | ast::TypeExpr const * rexpr = rparam->as<ast::TypeExpr>(); | 
|---|
|  | 554 | assertf( rexpr, "Aggregate parameters should be type expressions" ); | 
|---|
|  | 555 |  | 
|---|
|  | 556 | // xxx - might need to let VoidType be a wildcard here too; could have some voids | 
|---|
|  | 557 | // stuffed in for dtype-statics. | 
|---|
|  | 558 | // if ( is<VoidType>( lexpr->type() ) || is<VoidType>( bparam->get_type() ) ) continue; | 
|---|
|  | 559 | if ( !typesPolyCompatible( lexpr->type, rexpr->type ) ) { | 
|---|
|  | 560 | return false; | 
|---|
|  | 561 | } | 
|---|
|  | 562 | } | 
|---|
|  | 563 |  | 
|---|
|  | 564 | return true; | 
|---|
|  | 565 | } | 
|---|
| [5a3ac84] | 566 | } | 
|---|
|  | 567 |  | 
|---|
|  | 568 | bool typesPolyCompatible( Type *a, Type *b ) { | 
|---|
|  | 569 | type_index aid{ typeid(*a) }; | 
|---|
|  | 570 | // polymorphic types always match | 
|---|
|  | 571 | if ( aid == type_index{typeid(TypeInstType)} ) return true; | 
|---|
| [cccc534] | 572 |  | 
|---|
| [5a3ac84] | 573 | type_index bid{ typeid(*b) }; | 
|---|
|  | 574 | // polymorphic types always match | 
|---|
|  | 575 | if ( bid == type_index{typeid(TypeInstType)} ) return true; | 
|---|
| [cccc534] | 576 |  | 
|---|
| [5a3ac84] | 577 | // can't match otherwise if different types | 
|---|
|  | 578 | if ( aid != bid ) return false; | 
|---|
|  | 579 |  | 
|---|
|  | 580 | // recurse through type structure (conditions borrowed from Unify.cc) | 
|---|
|  | 581 | if ( aid == type_index{typeid(BasicType)} ) { | 
|---|
|  | 582 | return as<BasicType>(a)->get_kind() == as<BasicType>(b)->get_kind(); | 
|---|
|  | 583 | } else if ( aid == type_index{typeid(PointerType)} ) { | 
|---|
|  | 584 | PointerType *ap = as<PointerType>(a), *bp = as<PointerType>(b); | 
|---|
|  | 585 |  | 
|---|
|  | 586 | // void pointers should match any other pointer type | 
|---|
|  | 587 | return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() ) | 
|---|
|  | 588 | || typesPolyCompatible( ap->get_base(), bp->get_base() ); | 
|---|
| [682dcae] | 589 | } else if ( aid == type_index{typeid(ReferenceType)} ) { | 
|---|
|  | 590 | ReferenceType *ap = as<ReferenceType>(a), *bp = as<ReferenceType>(b); | 
|---|
|  | 591 | return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() ) | 
|---|
|  | 592 | || typesPolyCompatible( ap->get_base(), bp->get_base() ); | 
|---|
| [5a3ac84] | 593 | } else if ( aid == type_index{typeid(ArrayType)} ) { | 
|---|
|  | 594 | ArrayType *aa = as<ArrayType>(a), *ba = as<ArrayType>(b); | 
|---|
|  | 595 |  | 
|---|
|  | 596 | if ( aa->get_isVarLen() ) { | 
|---|
|  | 597 | if ( ! ba->get_isVarLen() ) return false; | 
|---|
|  | 598 | } else { | 
|---|
|  | 599 | if ( ba->get_isVarLen() ) return false; | 
|---|
|  | 600 |  | 
|---|
|  | 601 | ConstantExpr *ad = dynamic_cast<ConstantExpr*>( aa->get_dimension() ); | 
|---|
|  | 602 | ConstantExpr *bd = dynamic_cast<ConstantExpr*>( ba->get_dimension() ); | 
|---|
| [cccc534] | 603 | if ( ad && bd | 
|---|
| [5a3ac84] | 604 | && ad->get_constant()->get_value() != bd->get_constant()->get_value() ) | 
|---|
|  | 605 | return false; | 
|---|
|  | 606 | } | 
|---|
|  | 607 |  | 
|---|
|  | 608 | return typesPolyCompatible( aa->get_base(), ba->get_base() ); | 
|---|
|  | 609 | } else if ( aid == type_index{typeid(FunctionType)} ) { | 
|---|
|  | 610 | FunctionType *af = as<FunctionType>(a), *bf = as<FunctionType>(b); | 
|---|
|  | 611 |  | 
|---|
|  | 612 | vector<Type*> aparams, bparams; | 
|---|
|  | 613 | flattenList( af->get_parameters(), back_inserter( aparams ) ); | 
|---|
|  | 614 | flattenList( bf->get_parameters(), back_inserter( bparams ) ); | 
|---|
|  | 615 | if ( aparams.size() != bparams.size() ) return false; | 
|---|
|  | 616 |  | 
|---|
|  | 617 | vector<Type*> areturns, breturns; | 
|---|
|  | 618 | flattenList( af->get_returnVals(), back_inserter( areturns ) ); | 
|---|
|  | 619 | flattenList( bf->get_returnVals(), back_inserter( breturns ) ); | 
|---|
|  | 620 | if ( areturns.size() != breturns.size() ) return false; | 
|---|
|  | 621 |  | 
|---|
|  | 622 | for ( unsigned i = 0; i < aparams.size(); ++i ) { | 
|---|
|  | 623 | if ( ! typesPolyCompatible( aparams[i], bparams[i] ) ) return false; | 
|---|
|  | 624 | } | 
|---|
|  | 625 | for ( unsigned i = 0; i < areturns.size(); ++i ) { | 
|---|
|  | 626 | if ( ! typesPolyCompatible( areturns[i], breturns[i] ) ) return false; | 
|---|
|  | 627 | } | 
|---|
|  | 628 | return true; | 
|---|
|  | 629 | } else if ( aid == type_index{typeid(StructInstType)} ) { | 
|---|
|  | 630 | StructInstType *aa = as<StructInstType>(a), *ba = as<StructInstType>(b); | 
|---|
|  | 631 |  | 
|---|
|  | 632 | if ( aa->get_name() != ba->get_name() ) return false; | 
|---|
|  | 633 | return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() ); | 
|---|
|  | 634 | } else if ( aid == type_index{typeid(UnionInstType)} ) { | 
|---|
|  | 635 | UnionInstType *aa = as<UnionInstType>(a), *ba = as<UnionInstType>(b); | 
|---|
|  | 636 |  | 
|---|
|  | 637 | if ( aa->get_name() != ba->get_name() ) return false; | 
|---|
|  | 638 | return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() ); | 
|---|
|  | 639 | } else if ( aid == type_index{typeid(EnumInstType)} ) { | 
|---|
|  | 640 | return as<EnumInstType>(a)->get_name() == as<EnumInstType>(b)->get_name(); | 
|---|
|  | 641 | } else if ( aid == type_index{typeid(TraitInstType)} ) { | 
|---|
|  | 642 | return as<TraitInstType>(a)->get_name() == as<TraitInstType>(b)->get_name(); | 
|---|
|  | 643 | } else if ( aid == type_index{typeid(TupleType)} ) { | 
|---|
|  | 644 | TupleType *at = as<TupleType>(a), *bt = as<TupleType>(b); | 
|---|
|  | 645 |  | 
|---|
|  | 646 | vector<Type*> atypes, btypes; | 
|---|
|  | 647 | flattenList( at->get_types(), back_inserter( atypes ) ); | 
|---|
|  | 648 | flattenList( bt->get_types(), back_inserter( btypes ) ); | 
|---|
|  | 649 | if ( atypes.size() != btypes.size() ) return false; | 
|---|
|  | 650 |  | 
|---|
|  | 651 | for ( unsigned i = 0; i < atypes.size(); ++i ) { | 
|---|
|  | 652 | if ( ! typesPolyCompatible( atypes[i], btypes[i] ) ) return false; | 
|---|
|  | 653 | } | 
|---|
|  | 654 | return true; | 
|---|
|  | 655 | } else return true; // VoidType, VarArgsType, ZeroType & OneType just need the same type | 
|---|
|  | 656 | } | 
|---|
|  | 657 |  | 
|---|
| [3606fe4] | 658 | bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ) { | 
|---|
|  | 659 | type_index const lid = typeid(*lhs); | 
|---|
|  | 660 |  | 
|---|
|  | 661 | // Polymorphic types always match: | 
|---|
|  | 662 | if ( type_index(typeid(ast::TypeInstType)) == lid ) return true; | 
|---|
|  | 663 |  | 
|---|
|  | 664 | type_index const rid = typeid(*rhs); | 
|---|
|  | 665 | if ( type_index(typeid(ast::TypeInstType)) == rid ) return true; | 
|---|
|  | 666 |  | 
|---|
|  | 667 | // All other types only match if they are the same type: | 
|---|
|  | 668 | if ( lid != rid ) return false; | 
|---|
|  | 669 |  | 
|---|
|  | 670 | // So remaining types can be examined case by case. | 
|---|
|  | 671 | // Recurse through type structure (conditions borrowed from Unify.cc). | 
|---|
|  | 672 |  | 
|---|
|  | 673 | if ( type_index(typeid(ast::BasicType)) == lid ) { | 
|---|
|  | 674 | return as<ast::BasicType>(lhs)->kind == as<ast::BasicType>(rhs)->kind; | 
|---|
|  | 675 | } else if ( type_index(typeid(ast::PointerType)) == lid ) { | 
|---|
|  | 676 | ast::PointerType const * l = as<ast::PointerType>(lhs); | 
|---|
|  | 677 | ast::PointerType const * r = as<ast::PointerType>(rhs); | 
|---|
|  | 678 |  | 
|---|
|  | 679 | // void pointers should match any other pointer type. | 
|---|
|  | 680 | return is<ast::VoidType>( l->base.get() ) | 
|---|
|  | 681 | || is<ast::VoidType>( r->base.get() ) | 
|---|
|  | 682 | || typesPolyCompatible( l->base.get(), r->base.get() ); | 
|---|
|  | 683 | } else if ( type_index(typeid(ast::ReferenceType)) == lid ) { | 
|---|
|  | 684 | ast::ReferenceType const * l = as<ast::ReferenceType>(lhs); | 
|---|
|  | 685 | ast::ReferenceType const * r = as<ast::ReferenceType>(rhs); | 
|---|
|  | 686 |  | 
|---|
|  | 687 | // void references should match any other reference type. | 
|---|
|  | 688 | return is<ast::VoidType>( l->base.get() ) | 
|---|
|  | 689 | || is<ast::VoidType>( r->base.get() ) | 
|---|
|  | 690 | || typesPolyCompatible( l->base.get(), r->base.get() ); | 
|---|
|  | 691 | } else if ( type_index(typeid(ast::ArrayType)) == lid ) { | 
|---|
|  | 692 | ast::ArrayType const * l = as<ast::ArrayType>(lhs); | 
|---|
|  | 693 | ast::ArrayType const * r = as<ast::ArrayType>(rhs); | 
|---|
|  | 694 |  | 
|---|
|  | 695 | if ( l->isVarLen ) { | 
|---|
|  | 696 | if ( !r->isVarLen ) return false; | 
|---|
|  | 697 | } else { | 
|---|
|  | 698 | if ( r->isVarLen ) return false; | 
|---|
|  | 699 |  | 
|---|
|  | 700 | auto lc = l->dimension.as<ast::ConstantExpr>(); | 
|---|
|  | 701 | auto rc = r->dimension.as<ast::ConstantExpr>(); | 
|---|
|  | 702 | if ( lc && rc && lc->intValue() != rc->intValue() ) { | 
|---|
|  | 703 | return false; | 
|---|
|  | 704 | } | 
|---|
|  | 705 | } | 
|---|
|  | 706 |  | 
|---|
|  | 707 | return typesPolyCompatible( l->base.get(), r->base.get() ); | 
|---|
|  | 708 | } else if ( type_index(typeid(ast::FunctionType)) == lid ) { | 
|---|
|  | 709 | ast::FunctionType const * l = as<ast::FunctionType>(lhs); | 
|---|
|  | 710 | ast::FunctionType const * r = as<ast::FunctionType>(rhs); | 
|---|
|  | 711 |  | 
|---|
|  | 712 | std::vector<ast::ptr<ast::Type>> lparams, rparams; | 
|---|
|  | 713 | flattenList( l->params, lparams ); | 
|---|
|  | 714 | flattenList( r->params, rparams ); | 
|---|
|  | 715 | if ( lparams.size() != rparams.size() ) return false; | 
|---|
|  | 716 | for ( unsigned i = 0; i < lparams.size(); ++i ) { | 
|---|
|  | 717 | if ( !typesPolyCompatible( lparams[i], rparams[i] ) ) return false; | 
|---|
|  | 718 | } | 
|---|
|  | 719 |  | 
|---|
|  | 720 | std::vector<ast::ptr<ast::Type>> lrets, rrets; | 
|---|
|  | 721 | flattenList( l->returns, lrets ); | 
|---|
|  | 722 | flattenList( r->returns, rrets ); | 
|---|
|  | 723 | if ( lrets.size() != rrets.size() ) return false; | 
|---|
|  | 724 | for ( unsigned i = 0; i < lrets.size(); ++i ) { | 
|---|
|  | 725 | if ( !typesPolyCompatible( lrets[i], rrets[i] ) ) return false; | 
|---|
|  | 726 | } | 
|---|
|  | 727 | return true; | 
|---|
|  | 728 | } else if ( type_index(typeid(ast::StructInstType)) == lid ) { | 
|---|
|  | 729 | ast::StructInstType const * l = as<ast::StructInstType>(lhs); | 
|---|
|  | 730 | ast::StructInstType const * r = as<ast::StructInstType>(rhs); | 
|---|
|  | 731 |  | 
|---|
|  | 732 | if ( l->name != r->name ) return false; | 
|---|
|  | 733 | return paramListsPolyCompatible( l->params, r->params ); | 
|---|
|  | 734 | } else if ( type_index(typeid(ast::UnionInstType)) == lid ) { | 
|---|
|  | 735 | ast::UnionInstType const * l = as<ast::UnionInstType>(lhs); | 
|---|
|  | 736 | ast::UnionInstType const * r = as<ast::UnionInstType>(rhs); | 
|---|
|  | 737 |  | 
|---|
|  | 738 | if ( l->name != r->name ) return false; | 
|---|
|  | 739 | return paramListsPolyCompatible( l->params, r->params ); | 
|---|
|  | 740 | } else if ( type_index(typeid(ast::EnumInstType)) == lid ) { | 
|---|
|  | 741 | ast::EnumInstType const * l = as<ast::EnumInstType>(lhs); | 
|---|
|  | 742 | ast::EnumInstType const * r = as<ast::EnumInstType>(rhs); | 
|---|
|  | 743 |  | 
|---|
|  | 744 | return l->name == r->name; | 
|---|
|  | 745 | } else if ( type_index(typeid(ast::TraitInstType)) == lid ) { | 
|---|
|  | 746 | ast::TraitInstType const * l = as<ast::TraitInstType>(lhs); | 
|---|
|  | 747 | ast::TraitInstType const * r = as<ast::TraitInstType>(rhs); | 
|---|
|  | 748 |  | 
|---|
|  | 749 | return l->name == r->name; | 
|---|
|  | 750 | } else if ( type_index(typeid(ast::TupleType)) == lid ) { | 
|---|
|  | 751 | ast::TupleType const * l = as<ast::TupleType>(lhs); | 
|---|
|  | 752 | ast::TupleType const * r = as<ast::TupleType>(rhs); | 
|---|
|  | 753 |  | 
|---|
|  | 754 | std::vector<ast::ptr<ast::Type>> ltypes, rtypes; | 
|---|
|  | 755 | flattenList( l->types, ( ltypes ) ); | 
|---|
|  | 756 | flattenList( r->types, ( rtypes ) ); | 
|---|
|  | 757 | if ( ltypes.size() != rtypes.size() ) return false; | 
|---|
|  | 758 |  | 
|---|
|  | 759 | for ( unsigned i = 0 ; i < ltypes.size() ; ++i ) { | 
|---|
|  | 760 | if ( !typesPolyCompatible( ltypes[i], rtypes[i] ) ) return false; | 
|---|
|  | 761 | } | 
|---|
|  | 762 | return true; | 
|---|
|  | 763 | // The remaining types (VoidType, VarArgsType, ZeroType & OneType) | 
|---|
|  | 764 | // have no variation so will always be equal. | 
|---|
|  | 765 | } else { | 
|---|
|  | 766 | return true; | 
|---|
|  | 767 | } | 
|---|
|  | 768 | } | 
|---|
|  | 769 |  | 
|---|
| [02fdb8e] | 770 | bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) { | 
|---|
| [ae1b9ea] | 771 | // is parameter is not polymorphic, don't need to box | 
|---|
|  | 772 | if ( ! isPolyType( param, exprTyVars ) ) return false; | 
|---|
|  | 773 | Type * newType = arg->clone(); | 
|---|
|  | 774 | if ( env ) env->apply( newType ); | 
|---|
|  | 775 | std::unique_ptr<Type> manager( newType ); | 
|---|
|  | 776 | // if the argument's type is polymorphic, we don't need to box again! | 
|---|
|  | 777 | return ! isPolyType( newType ); | 
|---|
|  | 778 | } | 
|---|
|  | 779 |  | 
|---|
| [c8837e5] | 780 | bool needsBoxing( const ast::Type * param, const ast::Type * arg, | 
|---|
|  | 781 | const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { | 
|---|
|  | 782 | // Don't need to box if the parameter is not polymorphic. | 
|---|
|  | 783 | if ( !isPolyType( param, typeVars ) ) return false; | 
|---|
|  | 784 |  | 
|---|
|  | 785 | ast::ptr<ast::Type> newType = arg; | 
|---|
|  | 786 | if ( subst ) { | 
|---|
|  | 787 | int count = subst->apply( newType ); | 
|---|
|  | 788 | (void)count; | 
|---|
| [490fb92e] | 789 | } | 
|---|
| [c8837e5] | 790 | // Only need to box if the argument is not also polymorphic. | 
|---|
|  | 791 | return !isPolyType( newType ); | 
|---|
|  | 792 | } | 
|---|
| [490fb92e] | 793 |  | 
|---|
| [02fdb8e] | 794 | bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) { | 
|---|
| [ae1b9ea] | 795 | FunctionType * function = getFunctionType( appExpr->function->result ); | 
|---|
|  | 796 | assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() ); | 
|---|
|  | 797 | TyVarMap exprTyVars( TypeDecl::Data{} ); | 
|---|
|  | 798 | makeTyVarMap( function, exprTyVars ); | 
|---|
|  | 799 | return needsBoxing( param, arg, exprTyVars, env ); | 
|---|
|  | 800 | } | 
|---|
|  | 801 |  | 
|---|
| [c8837e5] | 802 | bool needsBoxing( | 
|---|
|  | 803 | const ast::Type * param, const ast::Type * arg, | 
|---|
|  | 804 | const ast::ApplicationExpr * expr, | 
|---|
|  | 805 | const ast::TypeSubstitution * subst ) { | 
|---|
|  | 806 | const ast::FunctionType * function = getFunctionType( expr->func->result ); | 
|---|
|  | 807 | assertf( function, "ApplicationExpr has non-function type: %s", toString( expr->func->result ).c_str() ); | 
|---|
| [93c10de] | 808 | TypeVarMap exprTyVars = { ast::TypeData() }; | 
|---|
| [c8837e5] | 809 | makeTypeVarMap( function, exprTyVars ); | 
|---|
|  | 810 | return needsBoxing( param, arg, exprTyVars, subst ); | 
|---|
|  | 811 | } | 
|---|
| [490fb92e] | 812 |  | 
|---|
| [2c57025] | 813 | void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) { | 
|---|
| [7ba1324] | 814 | tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } ); | 
|---|
| [2c57025] | 815 | } | 
|---|
|  | 816 |  | 
|---|
| [c97b448] | 817 | void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) { | 
|---|
|  | 818 | typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) ); | 
|---|
|  | 819 | } | 
|---|
|  | 820 |  | 
|---|
| [c8837e5] | 821 | void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) { | 
|---|
| [c97b448] | 822 | typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) ); | 
|---|
| [c8837e5] | 823 | } | 
|---|
| [490fb92e] | 824 |  | 
|---|
| [aadc9a4] | 825 | void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) { | 
|---|
| [8c49c0e] | 826 | for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) { | 
|---|
| [aadc9a4] | 827 | assert( *tyVar ); | 
|---|
| [2c57025] | 828 | addToTyVarMap( *tyVar, tyVarMap ); | 
|---|
| [aadc9a4] | 829 | } | 
|---|
|  | 830 | if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) { | 
|---|
|  | 831 | makeTyVarMap( pointer->get_base(), tyVarMap ); | 
|---|
|  | 832 | } | 
|---|
|  | 833 | } | 
|---|
| [540de412] | 834 |  | 
|---|
| [c8837e5] | 835 | void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) { | 
|---|
|  | 836 | if ( auto func = dynamic_cast<ast::FunctionType const *>( type ) ) { | 
|---|
|  | 837 | for ( auto & typeVar : func->forall ) { | 
|---|
|  | 838 | assert( typeVar ); | 
|---|
|  | 839 | addToTypeVarMap( typeVar, typeVars ); | 
|---|
| [490fb92e] | 840 | } | 
|---|
|  | 841 | } | 
|---|
| [c8837e5] | 842 | if ( auto pointer = dynamic_cast<ast::PointerType const *>( type ) ) { | 
|---|
|  | 843 | makeTypeVarMap( pointer->base, typeVars ); | 
|---|
|  | 844 | } | 
|---|
|  | 845 | } | 
|---|
| [490fb92e] | 846 |  | 
|---|
| [c97b448] | 847 | void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ) { | 
|---|
|  | 848 | for ( auto & typeDecl : decl->type_params ) { | 
|---|
|  | 849 | addToTypeVarMap( typeDecl, typeVars ); | 
|---|
|  | 850 | } | 
|---|
|  | 851 | } | 
|---|
|  | 852 |  | 
|---|
| [01aeade] | 853 | void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) { | 
|---|
|  | 854 | for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) { | 
|---|
|  | 855 | os << i->first << " (" << i->second << ") "; | 
|---|
|  | 856 | } // for | 
|---|
|  | 857 | os << std::endl; | 
|---|
|  | 858 | } | 
|---|
| [ffad73a] | 859 |  | 
|---|
| [51b73452] | 860 | } // namespace GenPoly | 
|---|
| [01aeade] | 861 |  | 
|---|
| [51587aa] | 862 | // Local Variables: // | 
|---|
|  | 863 | // tab-width: 4 // | 
|---|
|  | 864 | // mode: c++ // | 
|---|
|  | 865 | // compile-command: "make install" // | 
|---|
|  | 866 | // End: // | 
|---|