Changeset c6b4432 for src/ResolvExpr
- Timestamp:
- Nov 8, 2023, 2:01:11 PM (23 months ago)
- Branches:
- master
- Children:
- 3e4bf0d, f5ec35a
- Parents:
- 790d835
- Location:
- src/ResolvExpr
- Files:
-
- 13 deleted
- 22 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/AdjustExprType.cc
r790d835 rc6b4432 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h"22 #include "SymTab/Indexer.h" // for Indexer23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype24 #include "SynTree/Mutator.h" // for Mutator25 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type26 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment27 21 28 22 namespace ResolvExpr { 29 30 namespace {31 class AdjustExprType_old final : public WithShortCircuiting {32 public:33 AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer );34 void premutate( VoidType * ) { visit_children = false; }35 void premutate( BasicType * ) { visit_children = false; }36 void premutate( PointerType * ) { visit_children = false; }37 void premutate( ArrayType * ) { visit_children = false; }38 void premutate( FunctionType * ) { visit_children = false; }39 void premutate( StructInstType * ) { visit_children = false; }40 void premutate( UnionInstType * ) { visit_children = false; }41 void premutate( EnumInstType * ) { visit_children = false; }42 void premutate( TraitInstType * ) { visit_children = false; }43 void premutate( TypeInstType * ) { visit_children = false; }44 void premutate( TupleType * ) { visit_children = false; }45 void premutate( VarArgsType * ) { visit_children = false; }46 void premutate( ZeroType * ) { visit_children = false; }47 void premutate( OneType * ) { visit_children = false; }48 49 Type * postmutate( ArrayType * arrayType );50 Type * postmutate( FunctionType * functionType );51 Type * postmutate( TypeInstType * aggregateUseType );52 53 private:54 const TypeEnvironment & env;55 const SymTab::Indexer & indexer;56 };57 58 AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer )59 : env( env ), indexer( indexer ) {60 }61 62 Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) {63 PointerType * pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };64 arrayType->base = nullptr;65 delete arrayType;66 return pointerType;67 }68 69 Type * AdjustExprType_old::postmutate( FunctionType * functionType ) {70 return new PointerType{ Type::Qualifiers(), functionType };71 }72 73 Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) {74 if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {75 if ( eqvClass->data.kind == TypeDecl::Ftype ) {76 return new PointerType{ Type::Qualifiers(), typeInst };77 }78 } else if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->get_name() ) ) {79 if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl * >( ntDecl ) ) {80 if ( tyDecl->get_kind() == TypeDecl::Ftype ) {81 return new PointerType{ Type::Qualifiers(), typeInst };82 } // if83 } // if84 } // if85 return typeInst;86 }87 } // anonymous namespace88 89 void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {90 PassVisitor<AdjustExprType_old> adjuster( env, indexer );91 Type * newType = type->acceptMutator( adjuster );92 type = newType;93 }94 95 void adjustExprType( Type *& type ) {96 TypeEnvironment env;97 SymTab::Indexer indexer;98 adjustExprType( type, env, indexer );99 }100 23 101 24 namespace { -
src/ResolvExpr/CastCost.cc
r790d835 rc6b4432 26 26 #include "ResolvExpr/ConversionCost.h" // for conversionCost 27 27 #include "ResolvExpr/PtrsCastable.hpp" // for ptrsCastable 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, EqvClass29 28 #include "ResolvExpr/typeops.h" // for ptrsCastable 30 29 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 31 #include "SymTab/Indexer.h" // for Indexer32 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl33 #include "SynTree/Type.h" // for PointerType, Type, TypeInstType34 30 35 31 #if 0 … … 40 36 41 37 namespace ResolvExpr { 42 struct CastCost_old : public ConversionCost {43 public:44 CastCost_old( const Type * dest, bool srcIsLvalue,45 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );46 47 using ConversionCost::previsit;48 using ConversionCost::postvisit;49 void postvisit( const BasicType * basicType );50 void postvisit( const PointerType * pointerType );51 };52 53 Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,54 const SymTab::Indexer &indexer, const TypeEnvironment &env ) {55 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {56 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {57 if ( eqvClass->type ) {58 return castCost( src, eqvClass->type, srcIsLvalue, indexer, env );59 } else {60 return Cost::infinity;61 }62 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {63 // all typedefs should be gone by this point64 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType );65 if ( type->base ) {66 return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe;67 } // if68 } // if69 } // if70 71 PRINT(72 std::cerr << "castCost ::: src is ";73 src->print( std::cerr );74 std::cerr << std::endl << "dest is ";75 dest->print( std::cerr );76 std::cerr << std::endl << "env is" << std::endl;77 env.print( std::cerr, 8 );78 )79 80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {81 PRINT( std::cerr << "compatible!" << std::endl; )82 return Cost::zero;83 } else if ( dynamic_cast< const VoidType * >( dest ) ) {84 return Cost::safe;85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {88 return ptrsCastable( t1, t2, env, indexer );89 });90 } else {91 PassVisitor<CastCost_old> converter(92 dest, srcIsLvalue, indexer, env,93 (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & ))94 castCost );95 src->accept( converter );96 if ( converter.pass.get_cost() == Cost::infinity ) {97 return Cost::infinity;98 } else {99 // xxx - why are we adding cost 0 here?100 return converter.pass.get_cost() + Cost::zero;101 } // if102 } // if103 }104 105 CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue,106 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )107 : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) {108 }109 110 void CastCost_old::postvisit( const BasicType * basicType ) {111 const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest );112 if ( destAsPointer && basicType->isInteger() ) {113 // necessary for, e.g. unsigned long => void *114 cost = Cost::unsafe;115 } else {116 cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env );117 } // if118 }119 120 void CastCost_old::postvisit( const PointerType * pointerType ) {121 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {122 if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {123 cost = Cost::safe;124 } else {125 TypeEnvironment newEnv( env );126 newEnv.add( pointerType->forall );127 newEnv.add( pointerType->base->forall );128 int castResult = ptrsCastable( pointerType->base, destAsPtr->base, newEnv, indexer );129 if ( castResult > 0 ) {130 cost = Cost::safe;131 } else if ( castResult < 0 ) {132 cost = Cost::infinity;133 } // if134 } // if135 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {136 if ( destAsBasic->isInteger() ) {137 // necessary for, e.g. void * => unsigned long138 cost = Cost::unsafe;139 } // if140 }141 }142 38 143 39 namespace { … … 200 96 } // anonymous namespace 201 97 202 203 204 98 Cost castCost( 205 99 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, -
src/ResolvExpr/CommonType.cc
r790d835 rc6b4432 23 23 #include "AST/Pass.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h"26 #include "ResolvExpr/TypeEnvironment.h" // for OpenVarSet, AssertionSet27 #include "SymTab/Indexer.h" // for Indexer28 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl (ptr...29 #include "SynTree/Type.h" // for BasicType, BasicType::Kind::...30 #include "SynTree/Visitor.h" // for Visitor31 25 #include "Unify.h" // for unifyExact, WidenMode 32 26 #include "typeops.h" // for isFtype … … 41 35 42 36 namespace ResolvExpr { 43 struct CommonType_old : public WithShortCircuiting {44 CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );45 Type * get_result() const { return result; }46 47 void previsit( BaseSyntaxNode * ) { visit_children = false; }48 49 void postvisit( VoidType * voidType );50 void postvisit( BasicType * basicType );51 void postvisit( PointerType * pointerType );52 void postvisit( ArrayType * arrayType );53 void postvisit( ReferenceType * refType );54 void postvisit( FunctionType * functionType );55 void postvisit( StructInstType * aggregateUseType );56 void postvisit( UnionInstType * aggregateUseType );57 void postvisit( EnumInstType * aggregateUseType );58 void postvisit( TraitInstType * aggregateUseType );59 void postvisit( TypeInstType * aggregateUseType );60 void postvisit( TupleType * tupleType );61 void postvisit( VarArgsType * varArgsType );62 void postvisit( ZeroType * zeroType );63 void postvisit( OneType * oneType );64 65 private:66 template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer );67 template< typename RefType > void handleRefType( RefType * inst, Type * other );68 69 Type * result;70 Type * type2; // inherited71 bool widenFirst, widenSecond;72 const SymTab::Indexer &indexer;73 TypeEnvironment &env;74 const OpenVarSet &openVars;75 };76 77 Type * handleReference( Type * t1, Type * t2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {78 Type * common = nullptr;79 AssertionSet have, need;80 OpenVarSet newOpen( openVars );81 // need unify to bind type variables82 if ( unify( t1, t2, env, have, need, newOpen, indexer, common ) ) {83 PRINT(84 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;85 )86 if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) {87 PRINT(88 std::cerr << "widen okay" << std::endl;89 )90 common->tq |= t1->tq;91 common->tq |= t2->tq;92 return common;93 }94 }95 PRINT(96 std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;97 )98 return nullptr;99 }100 101 Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {102 PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );103 104 int depth1 = type1->referenceDepth();105 int depth2 = type2->referenceDepth();106 if ( depth1 > 0 || depth2 > 0 ) {107 int diff = depth1-depth2;108 // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed.109 // if ( diff > 1 || diff < -1 ) return nullptr;110 111 // special case where one type has a reference depth of 1 larger than the other112 if ( diff > 0 || diff < 0 ) {113 PRINT(114 std::cerr << "reference depth diff: " << diff << std::endl;115 )116 Type * result = nullptr;117 ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 );118 ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 );119 if ( diff > 0 ) {120 // deeper on the left121 assert( ref1 );122 result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );123 } else {124 // deeper on the right125 assert( ref2 );126 result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );127 }128 if ( result && ref1 ) {129 // formal is reference, so result should be reference130 PRINT(131 std::cerr << "formal is reference; result should be reference" << std::endl;132 )133 result = new ReferenceType( ref1->tq, result );134 }135 PRINT(136 std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl;137 )138 return result;139 }140 // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor.141 }142 143 type1->accept( visitor );144 Type * result = visitor.pass.get_result();145 if ( ! result ) {146 // this appears to be handling for opaque type declarations147 if ( widenSecond ) {148 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) {149 if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) {150 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );151 if ( type->get_base() ) {152 Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq;153 AssertionSet have, need;154 OpenVarSet newOpen( openVars );155 type1->tq = Type::Qualifiers();156 type->get_base()->tq = tq1;157 if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) {158 result = type1->clone();159 result->tq = tq1 | tq2;160 } // if161 type1->tq = tq1;162 type->get_base()->tq = Type::Qualifiers();163 } // if164 } // if165 } // if166 } // if167 } // if168 #ifdef DEBUG169 std::cerr << "============= commonType" << std::endl << "type1 is ";170 type1->print( std::cerr );171 std::cerr << " type2 is ";172 type2->print( std::cerr );173 if ( result ) {174 std::cerr << " common type is ";175 result->print( std::cerr );176 } else {177 std::cerr << " no common type";178 } // if179 std::cerr << std::endl;180 #endif181 return result;182 }183 37 184 38 // GENERATED START, DO NOT EDIT … … 488 342 "Each basic type kind should have a corresponding row in the combined type matrix" 489 343 ); 490 491 CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars )492 : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) {493 }494 495 void CommonType_old::postvisit( VoidType * ) {}496 497 void CommonType_old::postvisit( BasicType * basicType ) {498 if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) {499 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ (ast::BasicType::Kind)(int)otherBasic->get_kind() ];500 if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) {501 result = new BasicType( basicType->tq | otherBasic->tq, newType );502 } // if503 } else if ( dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {504 // use signed int in lieu of the enum/zero/one type505 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ ast::BasicType::SignedInt ];506 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {507 result = new BasicType( basicType->tq | type2->tq, newType );508 } // if509 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) {510 const EnumDecl* enumDecl = enumInst->baseEnum;511 if ( const Type* baseType = enumDecl->base ) {512 result = baseType->clone();513 } else {514 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ ast::BasicType::SignedInt ];515 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {516 result = new BasicType( basicType->tq | type2->tq, newType );517 } // if518 }519 }520 }521 522 template< typename Pointer >523 void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) {524 if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) {525 OpenVarSet::const_iterator entry = openVars.find( var->get_name() );526 if ( entry != openVars.end() ) {527 AssertionSet need, have;528 WidenMode widen( widenFirst, widenSecond );529 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return;530 }531 }532 result = voidPointer->clone();533 result->tq |= otherPointer->tq;534 }535 536 void CommonType_old::postvisit( PointerType * pointerType ) {537 if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) {538 // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;539 if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {540 getCommonWithVoidPointer( otherPointer, pointerType );541 } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {542 getCommonWithVoidPointer( pointerType, otherPointer );543 } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst )544 && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) {545 // std::cerr << "middle case" << std::endl;546 Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq;547 pointerType->get_base()->tq = Type::Qualifiers();548 otherPointer->get_base()->tq = Type::Qualifiers();549 AssertionSet have, need;550 OpenVarSet newOpen( openVars );551 if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) {552 // std::cerr << "unifyExact success" << std::endl;553 if ( tq1 < tq2 ) {554 result = pointerType->clone();555 } else {556 result = otherPointer->clone();557 } // if558 strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2;559 } else {560 /// std::cerr << "place for ptr-to-type" << std::endl;561 } // if562 pointerType->get_base()->tq = tq1;563 otherPointer->get_base()->tq = tq2;564 } // if565 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {566 result = pointerType->clone();567 result->tq |= type2->tq;568 } // if569 }570 571 void CommonType_old::postvisit( ArrayType * ) {}572 573 void CommonType_old::postvisit( ReferenceType * refType ) {574 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) {575 // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;576 // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl;577 if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {578 getCommonWithVoidPointer( otherRef, refType );579 } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {580 getCommonWithVoidPointer( refType, otherRef );581 } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst )582 && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) {583 // std::cerr << "middle case" << std::endl;584 Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq;585 refType->get_base()->tq = Type::Qualifiers();586 otherRef->get_base()->tq = Type::Qualifiers();587 AssertionSet have, need;588 OpenVarSet newOpen( openVars );589 if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) {590 if ( tq1 < tq2 ) {591 result = refType->clone();592 } else {593 result = otherRef->clone();594 } // if595 strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2;596 } else {597 /// std::cerr << "place for ptr-to-type" << std::endl;598 } // if599 refType->get_base()->tq = tq1;600 otherRef->get_base()->tq = tq2;601 } // if602 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {603 result = refType->clone();604 result->tq |= type2->tq;605 } // if606 }607 608 void CommonType_old::postvisit( FunctionType * ) {}609 void CommonType_old::postvisit( StructInstType * ) {}610 void CommonType_old::postvisit( UnionInstType * ) {}611 612 void CommonType_old::postvisit( EnumInstType * enumInstType ) {613 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {614 // reuse BasicType, EnumInstType code by swapping type2 with enumInstType615 result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );616 } // if617 }618 619 void CommonType_old::postvisit( TraitInstType * ) {620 }621 622 void CommonType_old::postvisit( TypeInstType * inst ) {623 if ( widenFirst ) {624 const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() );625 if ( nt ) {626 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );627 if ( type->get_base() ) {628 Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq;629 AssertionSet have, need;630 OpenVarSet newOpen( openVars );631 type2->tq = Type::Qualifiers();632 type->get_base()->tq = tq1;633 if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) {634 result = type2->clone();635 result->tq = tq1 | tq2;636 } // if637 type2->tq = tq2;638 type->get_base()->tq = Type::Qualifiers();639 } // if640 } // if641 } // if642 }643 644 void CommonType_old::postvisit( TupleType * ) {}645 void CommonType_old::postvisit( VarArgsType * ) {}646 647 void CommonType_old::postvisit( ZeroType * zeroType ) {648 if ( widenFirst ) {649 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {650 if ( widenSecond || zeroType->tq <= type2->tq ) {651 result = type2->clone();652 result->tq |= zeroType->tq;653 }654 } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) {655 result = new BasicType( zeroType->tq, BasicType::SignedInt );656 result->tq |= type2->tq;657 }658 }659 }660 661 void CommonType_old::postvisit( OneType * oneType ) {662 if ( widenFirst ) {663 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {664 if ( widenSecond || oneType->tq <= type2->tq ) {665 result = type2->clone();666 result->tq |= oneType->tq;667 }668 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {669 result = new BasicType( oneType->tq, BasicType::SignedInt );670 result->tq |= type2->tq;671 }672 }673 }674 344 675 345 class CommonType_new final : public ast::WithShortCircuiting { -
src/ResolvExpr/CommonType.hpp
r790d835 rc6b4432 18 18 #include "AST/Fwd.hpp" 19 19 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 20 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet21 20 #include "WidenMode.h" // for WidenMode 22 23 class Type;24 namespace SymTab {25 class Indexer;26 }27 21 28 22 namespace ResolvExpr { 29 23 30 Type * commonType(31 Type * type1, Type * type2, bool widenFirst, bool widenSecond,32 const SymTab::Indexer & indexer, TypeEnvironment & env,33 const OpenVarSet & openVars );34 24 ast::ptr< ast::Type > commonType( 35 25 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, -
src/ResolvExpr/ConversionCost.cc
r790d835 rc6b4432 21 21 22 22 #include "ResolvExpr/Cost.h" // for Cost 23 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment24 23 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 25 24 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 26 #include "SymTab/Indexer.h" // for Indexer27 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl28 #include "SynTree/Type.h" // for Type, BasicType, TypeInstType29 30 25 31 26 namespace ResolvExpr { 32 #if 033 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0, 0 };34 const Cost Cost::infinity = Cost{ -1, -1, -1, -1, -1, 1, -1 };35 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0, 0 };36 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0, 0 };37 const Cost Cost::safe = Cost{ 0, 0, 1, 0, 0, 0, 0 };38 const Cost Cost::sign = Cost{ 0, 0, 0, 1, 0, 0, 0 };39 const Cost Cost::var = Cost{ 0, 0, 0, 0, 1, 0, 0 };40 const Cost Cost::spec = Cost{ 0, 0, 0, 0, 0, -1, 0 };41 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 0, 1 };42 #endif43 27 44 28 #if 0 … … 47 31 #define PRINT(x) 48 32 #endif 49 50 Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,51 const SymTab::Indexer &indexer, const TypeEnvironment &env ) {52 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {53 PRINT( std::cerr << "type inst " << destAsTypeInst->name; )54 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {55 if ( eqvClass->type ) {56 return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env );57 } else {58 return Cost::infinity;59 }60 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {61 PRINT( std::cerr << " found" << std::endl; )62 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );63 // all typedefs should be gone by this point64 assert( type );65 if ( type->base ) {66 return conversionCost( src, type->base, srcIsLvalue, indexer, env )67 + Cost::safe;68 } // if69 } // if70 PRINT( std::cerr << " not found" << std::endl; )71 } // if72 PRINT(73 std::cerr << "src is ";74 src->print( std::cerr );75 std::cerr << std::endl << "dest is ";76 dest->print( std::cerr );77 std::cerr << std::endl << "env is" << std::endl;78 env.print( std::cerr, 8 );79 )80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {81 PRINT( std::cerr << "compatible!" << std::endl; )82 return Cost::zero;83 } else if ( dynamic_cast< const VoidType * >( dest ) ) {84 return Cost::safe;85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){88 return ptrsAssignable( t1, t2, env );89 });90 } else {91 PassVisitor<ConversionCost> converter(92 dest, srcIsLvalue, indexer, env,93 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))94 conversionCost );95 src->accept( converter );96 if ( converter.pass.get_cost() == Cost::infinity ) {97 return Cost::infinity;98 } else {99 return converter.pass.get_cost() + Cost::zero;100 } // if101 } // if102 }103 104 static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue,105 int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {106 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )107 if ( diff > 0 ) {108 // TODO: document this109 Cost cost = convertToReferenceCost(110 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue,111 diff-1, indexer, env, func );112 cost.incReference();113 return cost;114 } else if ( diff < -1 ) {115 // TODO: document this116 Cost cost = convertToReferenceCost(117 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue,118 diff+1, indexer, env, func );119 cost.incReference();120 return cost;121 } else if ( diff == 0 ) {122 const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src );123 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );124 if ( srcAsRef && destAsRef ) { // pointer-like conversions between references125 PRINT( std::cerr << "converting between references" << std::endl; )126 Type::Qualifiers tq1 = srcAsRef->base->tq;127 Type::Qualifiers tq2 = destAsRef->base->tq;128 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {129 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )130 if ( tq1 == tq2 ) {131 // types are the same132 return Cost::zero;133 } else {134 // types are the same, except otherPointer has more qualifiers135 return Cost::safe;136 }137 } else { // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?138 int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env );139 PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )140 if ( assignResult > 0 ) {141 return Cost::safe;142 } else if ( assignResult < 0 ) {143 return Cost::unsafe;144 } // if145 } // if146 } else {147 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )148 PassVisitor<ConversionCost> converter(149 dest, srcIsLvalue, indexer, env,150 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))151 conversionCost );152 src->accept( converter );153 return converter.pass.get_cost();154 } // if155 } else {156 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );157 assert( diff == -1 && destAsRef );158 PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )159 if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {160 PRINT( std::cerr << "converting compatible base type" << std::endl; )161 if ( srcIsLvalue ) {162 PRINT(163 std::cerr << "lvalue to reference conversion" << std::endl;164 std::cerr << src << " => " << destAsRef << std::endl;165 )166 // lvalue-to-reference conversion: cv lvalue T => cv T &167 if ( src->tq == destAsRef->base->tq ) {168 return Cost::reference; // cost needs to be non-zero to add cast169 } if ( src->tq < destAsRef->base->tq ) {170 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same171 } else {172 return Cost::unsafe;173 } // if174 } else if ( destAsRef->base->get_const() ) {175 PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )176 // rvalue-to-const-reference conversion: T => const T &177 return Cost::safe;178 } else {179 PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )180 // rvalue-to-reference conversion: T => T &181 return Cost::unsafe;182 } // if183 } // if184 PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )185 }186 return Cost::infinity;187 }188 189 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,190 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {191 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();192 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func );193 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )194 return cost;195 }196 197 ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )198 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {199 }200 33 201 34 // GENERATED START, DO NOT EDIT … … 319 152 ); 320 153 321 void ConversionCost::postvisit( const VoidType * ) {322 cost = Cost::infinity;323 }324 325 // refactor for code resue326 void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) {327 int tableResult = costMatrix[ src->kind ][ dest->kind ];328 if ( tableResult == -1 ) {329 cost = Cost::unsafe;330 } else {331 cost = Cost::zero;332 cost.incSafe( tableResult );333 cost.incSign( signMatrix[ src->kind ][ dest->kind ] );334 } // if335 } // ConversionCost::conversionCostFromBasicToBasic336 337 void ConversionCost::postvisit(const BasicType * basicType) {338 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {339 conversionCostFromBasicToBasic(basicType, destAsBasic);340 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) {341 const EnumDecl * base_enum = enumInst->baseEnum;342 if ( const Type * base = base_enum->base ) {343 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) {344 conversionCostFromBasicToBasic(basicType, enumBaseAstBasic);345 } else {346 cost = Cost::infinity;347 } // if348 } else {349 cost = Cost::unsafe;350 } // if351 } // if352 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t.353 }354 355 void ConversionCost::postvisit( const PointerType * pointerType ) {356 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {357 PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )358 Type::Qualifiers tq1 = pointerType->base->tq;359 Type::Qualifiers tq2 = destAsPtr->base->tq;360 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {361 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )362 if ( tq1 == tq2 ) {363 // types are the same364 cost = Cost::zero;365 } else {366 // types are the same, except otherPointer has more qualifiers367 cost = Cost::safe;368 } // if369 } else {370 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );371 PRINT( std::cerr << " :: " << assignResult << std::endl; )372 if ( assignResult > 0 && tq1 <= tq2 ) {373 // xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct?374 if ( tq1 == tq2 ) {375 cost = Cost::safe;376 } else if ( tq1 < tq2 ) {377 cost = Cost::safe+Cost::safe;378 }379 } else if ( assignResult < 0 ) {380 cost = Cost::unsafe;381 } // if382 // assignResult == 0 means Cost::Infinity383 } // if384 // case case for zero_t because it should not be possible to convert pointers to zero_t.385 } // if386 }387 388 void ConversionCost::postvisit( const ArrayType * ) {}389 390 void ConversionCost::postvisit( const ReferenceType * refType ) {391 // Note: dest can never be a reference, since it would have been caught in an earlier check392 assert( ! dynamic_cast< const ReferenceType * >( dest ) );393 // convert reference to rvalue: cv T1 & => T2394 // recursively compute conversion cost from T1 to T2.395 // cv can be safely dropped because of 'implicit dereference' behavior.396 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env );397 if ( refType->base->tq == dest->tq ) {398 cost.incReference(); // prefer exact qualifiers399 } else if ( refType->base->tq < dest->tq ) {400 cost.incSafe(); // then gaining qualifiers401 } else {402 cost.incUnsafe(); // lose qualifiers as last resort403 }404 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )405 }406 407 void ConversionCost::postvisit( const FunctionType * ) {}408 409 void ConversionCost::postvisit( const EnumInstType * enumInst) {410 const EnumDecl * enumDecl = enumInst -> baseEnum;411 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum412 cost = costFunc( enumType, dest, srcIsLvalue, indexer, env );413 } else {414 static Type::Qualifiers q;415 static BasicType integer( q, BasicType::SignedInt );416 cost = costFunc( &integer, dest, srcIsLvalue, indexer, env ); // safe if dest >= int417 } // if418 if ( cost < Cost::unsafe ) {419 cost.incSafe();420 } // if421 }422 423 void ConversionCost::postvisit( const TraitInstType * ) {}424 425 void ConversionCost::postvisit( const TypeInstType * inst ) {426 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {427 cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env );428 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) {429 if ( inst->name == destAsInst->name ) {430 cost = Cost::zero;431 }432 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) {433 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );434 // all typedefs should be gone by this point435 assert( type );436 if ( type->base ) {437 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;438 } // if439 } // if440 }441 442 void ConversionCost::postvisit( const TupleType * tupleType ) {443 Cost c = Cost::zero;444 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) {445 std::list< Type * >::const_iterator srcIt = tupleType->types.begin();446 std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();447 while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {448 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env );449 if ( newCost == Cost::infinity ) {450 return;451 } // if452 c += newCost;453 } // while454 if ( destIt != destAsTuple->types.end() ) {455 cost = Cost::infinity;456 } else {457 cost = c;458 } // if459 } // if460 }461 462 void ConversionCost::postvisit( const VarArgsType * ) {463 if ( dynamic_cast< const VarArgsType * >( dest ) ) {464 cost = Cost::zero;465 }466 }467 468 void ConversionCost::postvisit( const ZeroType * ) {469 if ( dynamic_cast< const ZeroType * >( dest ) ) {470 cost = Cost::zero;471 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {472 // copied from visit(BasicType *) for signed int, but +1 for safe conversions473 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];474 if ( tableResult == -1 ) {475 cost = Cost::unsafe;476 } else {477 cost = Cost::zero;478 cost.incSafe( tableResult + 1 );479 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );480 } // if481 } else if ( dynamic_cast< const PointerType * >( dest ) ) {482 cost = Cost::zero;483 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation484 } // if485 }486 487 void ConversionCost::postvisit( const OneType * ) {488 if ( dynamic_cast< const OneType * >( dest ) ) {489 cost = Cost::zero;490 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {491 // copied from visit(BasicType *) for signed int, but +1 for safe conversions492 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];493 if ( tableResult == -1 ) {494 cost = Cost::unsafe;495 } else {496 cost = Cost::zero;497 cost.incSafe( tableResult + 1 );498 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );499 } // if500 } // if501 }502 503 154 namespace { 504 155 # warning For overload resolution between the two versions. -
src/ResolvExpr/ConversionCost.h
r790d835 rc6b4432 22 22 #include "AST/Fwd.hpp" 23 23 #include "AST/Pass.hpp" // for WithShortCircuiting 24 #include "Common/PassVisitor.h"25 #include "SynTree/Visitor.h" // for Visitor26 #include "SynTree/SynTree.h" // for Visitor Nodes27 24 28 25 namespace SymTab { … … 32 29 namespace ResolvExpr { 33 30 class TypeEnvironment; 34 35 Cost conversionCost(36 const Type * src, const Type * dest, bool srcIsLvalue,37 const SymTab::Indexer & indexer, const TypeEnvironment & env );38 39 typedef std::function<Cost(const Type *, const Type *, bool,40 const SymTab::Indexer &, const TypeEnvironment &)> CostFunction;41 42 struct ConversionCost : public WithShortCircuiting {43 public:44 ConversionCost( const Type * dest, bool srcIsLvalue,45 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction );46 47 Cost get_cost() const { return cost; }48 49 void previsit( const BaseSyntaxNode * ) { visit_children = false; }50 51 void postvisit( const VoidType * voidType );52 void postvisit( const BasicType * basicType );53 void postvisit( const PointerType * pointerType );54 void postvisit( const ArrayType * arrayType );55 void postvisit( const ReferenceType * refType );56 void postvisit( const FunctionType * functionType );57 void postvisit( const EnumInstType * aggregateUseType );58 void postvisit( const TraitInstType * aggregateUseType );59 void postvisit( const TypeInstType * aggregateUseType );60 void postvisit( const TupleType * tupleType );61 void postvisit( const VarArgsType * varArgsType );62 void postvisit( const ZeroType * zeroType );63 void postvisit( const OneType * oneType );64 protected:65 const Type * dest;66 bool srcIsLvalue;67 const SymTab::Indexer &indexer;68 Cost cost;69 const TypeEnvironment &env;70 CostFunction costFunc;71 private:72 // refactor for code resue73 void conversionCostFromBasicToBasic( const BasicType * src, const BasicType* dest );74 };75 76 typedef std::function<int(const Type *, const Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction;77 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,78 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func );79 31 80 32 // Some function pointer types, differ in return type. -
src/ResolvExpr/CurrentObject.cc
r790d835 rc6b4432 33 33 #include "Common/utility.h" // for toString 34 34 #include "CurrentObject.h" 35 #include "SynTree/Constant.h" // for Constant36 #include "SynTree/Declaration.h" // for ObjectDecl, Declaration, Struc...37 #include "SynTree/Expression.h" // for InitAlternative, VariableExpr38 #include "SynTree/Initializer.h" // for Designation, operator<<39 #include "SynTree/Type.h" // for Type, StructInstType, UnionIns...40 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution41 35 42 36 #if 0 … … 45 39 #define PRINT(x) 46 40 #endif 47 48 namespace ResolvExpr {49 template< typename AggrInst >50 TypeSubstitution makeGenericSubstitution( AggrInst * inst ) {51 assert( inst );52 assert( inst->get_baseParameters() );53 std::list< TypeDecl * > baseParams = *inst->get_baseParameters();54 std::list< Expression * > typeSubs = inst->get_parameters();55 TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );56 return subs;57 }58 59 TypeSubstitution makeGenericSubstitution( Type * type ) {60 if ( StructInstType * inst = dynamic_cast< StructInstType * >( type ) ) {61 return makeGenericSubstitution( inst );62 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( type ) ) {63 return makeGenericSubstitution( inst );64 } else {65 return TypeSubstitution();66 }67 }68 69 class MemberIterator {70 public:71 virtual ~MemberIterator() {}72 73 /// walks the current object using the given designators as a guide74 virtual void setPosition( std::list< Expression * > & designators ) = 0;75 76 /// retrieve the list of possible Type/Designation pairs for the current position in the currect object77 virtual std::list<InitAlternative> operator*() const = 0;78 79 /// true if the iterator is not currently at the end80 virtual operator bool() const = 0;81 82 /// moves the iterator by one member in the current object83 virtual MemberIterator & bigStep() = 0;84 85 /// moves the iterator by one member in the current subobject86 virtual MemberIterator & smallStep() = 0;87 88 /// the type of the current object89 virtual Type * getType() = 0;90 91 /// the type of the current subobject92 virtual Type * getNext() = 0;93 94 /// printing for debug95 virtual void print( std::ostream & out, Indenter indent ) const = 0;96 97 /// helper for operator*; aggregates must add designator to each init alternative, but98 /// adding designators in operator* creates duplicates.99 virtual std::list<InitAlternative> first() const = 0; // should be protected100 };101 102 std::ostream & operator<<(std::ostream & out, const MemberIterator & it) {103 Indenter indenter;104 it.print( out, indenter );105 return out;106 }107 108 /// create a new MemberIterator that traverses a type correctly109 MemberIterator * createMemberIterator( Type * type );110 111 /// iterates "other" types, e.g. basic types, pointer types, etc. which do not change at list initializer entry112 class SimpleIterator : public MemberIterator {113 public:114 SimpleIterator( Type * type ) : type( type ) {}115 116 virtual void setPosition( std::list< Expression * > & designators ) {117 assertf( designators.empty(), "simple iterator given non-empty designator..." ); // xxx - might be semantic error118 }119 120 virtual std::list<InitAlternative> operator*() const { return first(); }121 virtual operator bool() const { return type; }122 123 // big step is the same as small step124 virtual MemberIterator & bigStep() { return smallStep(); }125 virtual MemberIterator & smallStep() {126 type = nullptr; // type is nullified on increment since SimpleIterators do not have members127 return *this;128 }129 130 virtual void print( std::ostream & out, __attribute__((unused)) Indenter indent ) const {131 out << "SimpleIterator(" << type << ")";132 }133 134 virtual Type * getType() { return type; }135 virtual Type * getNext() { return type; }136 137 protected:138 virtual std::list<InitAlternative> first() const {139 if ( type ) return std::list<InitAlternative>{ { type->clone(), new Designation( {} ) } };140 else return std::list<InitAlternative>{};141 }142 private:143 Type * type = nullptr;144 };145 146 class ArrayIterator : public MemberIterator {147 public:148 ArrayIterator( ArrayType * at ) : array( at ) {149 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )150 base = at->base;151 memberIter = createMemberIterator( base );152 if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=: " );153 setSize( at->dimension );154 }155 156 ~ArrayIterator() {157 delete memberIter;158 }159 160 private:161 void setSize( Expression * expr ) {162 auto res = eval( expr );163 if (res.second) {164 size = res.first;165 } else {166 SemanticError( expr->location, toString("Array designator must be a constant expression: ", expr) );167 }168 }169 170 public:171 void setPosition( Expression * expr ) {172 // need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions173 auto arg = eval( expr );174 index = arg.first;175 return;176 177 // if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {178 // try {179 // index = constExpr->intValue();180 // } catch( SemanticErrorException & ) {181 // SemanticError( expr, "Constant expression of non-integral type in array designator: " );182 // }183 // } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {184 // setPosition( castExpr->get_arg() );185 // } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {186 // EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );187 // assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );188 // long long int value;189 // if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {190 // index = value;191 // }192 // } else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {193 // index = 0; // xxx - get actual sizeof/alignof value?194 // } else {195 // assertf( false, "4 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );196 // }197 }198 199 virtual void setPosition( std::list< Expression * > & designators ) {200 if ( ! designators.empty() ) {201 setPosition( designators.front() );202 designators.pop_front();203 memberIter->setPosition( designators );204 }205 }206 207 virtual std::list<InitAlternative> operator*() const {208 return first();209 }210 211 virtual operator bool() const { return index < size; }212 213 virtual MemberIterator & bigStep() {214 PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )215 ++index;216 delete memberIter;217 if ( index < size ) memberIter = createMemberIterator( base );218 else memberIter = nullptr;219 return *this;220 }221 222 virtual MemberIterator & smallStep() {223 PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )224 if ( memberIter ) {225 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )226 memberIter->smallStep();227 if ( *memberIter ) {228 PRINT( std::cerr << "has valid member iter" << std::endl; )229 return *this;230 }231 }232 return bigStep();233 }234 235 virtual Type * getType() { return array; }236 virtual Type * getNext() { return base; }237 238 virtual std::list<InitAlternative> first() const {239 PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )240 if ( memberIter && *memberIter ) {241 std::list<InitAlternative> ret = memberIter->first();242 for ( InitAlternative & alt : ret ) {243 alt.designation->get_designators().push_front( new ConstantExpr( Constant::from_ulong( index ) ) );244 }245 return ret;246 }247 return std::list<InitAlternative>();248 }249 250 virtual void print( std::ostream & out, Indenter indent ) const {251 out << "ArrayIterator(Array of " << base << ")";252 if ( memberIter ) {253 Indenter childIndent = indent+1;254 out << std::endl << childIndent;255 memberIter->print( out, childIndent );256 }257 }258 259 private:260 ArrayType * array = nullptr;261 Type * base = nullptr;262 size_t index = 0;263 size_t size = 0;264 MemberIterator * memberIter = nullptr;265 };266 267 class AggregateIterator : public MemberIterator {268 public:269 typedef std::list<Declaration *> MemberList;270 typedef MemberList::const_iterator iterator;271 std::string kind = ""; // for debug272 std::string name;273 Type * inst = nullptr;274 const MemberList & members;275 iterator curMember;276 bool atbegin = true; // false at first {small,big}Step -- this aggr type is only added to the possibilities at the beginning277 Type * curType = nullptr;278 MemberIterator * memberIter = nullptr;279 mutable TypeSubstitution sub;280 281 AggregateIterator( const std::string & kind, const std::string & name, Type * inst, const MemberList & members ) : kind( kind ), name( name ), inst( inst ), members( members ), curMember( members.begin() ), sub( makeGenericSubstitution( inst ) ) {282 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )283 init();284 }285 286 virtual ~AggregateIterator() {287 delete memberIter;288 }289 290 bool init() {291 PRINT( std::cerr << "--init()--" << members.size() << std::endl; )292 if ( curMember != members.end() ) {293 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( *curMember ) ) {294 PRINT( std::cerr << "incremented to field: " << field << std::endl; )295 curType = field->get_type();296 memberIter = createMemberIterator( curType );297 return true;298 }299 }300 return false;301 }302 303 virtual std::list<InitAlternative> operator*() const {304 if (memberIter && *memberIter) {305 std::list<InitAlternative> ret = memberIter->first();306 PRINT( std::cerr << "sub: " << sub << std::endl; )307 for ( InitAlternative & alt : ret ) {308 PRINT( std::cerr << "iterating and adding designators" << std::endl; )309 alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );310 // need to substitute for generic types, so that casts are to concrete types311 PRINT( std::cerr << " type is: " << alt.type; )312 sub.apply( alt.type ); // also apply to designation??313 PRINT( std::cerr << " ==> " << alt.type << std::endl; )314 }315 return ret;316 }317 return std::list<InitAlternative>();318 }319 320 virtual void setPosition( std::list< Expression * > & designators ) {321 if ( ! designators.empty() ) {322 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( designators.front() ) ) {323 for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {324 if ( *curMember == varExpr->get_var() ) {325 designators.pop_front();326 delete memberIter;327 memberIter = createMemberIterator( varExpr->get_result() );328 curType = varExpr->get_result();329 atbegin = curMember == members.begin() && designators.empty(); // xxx - is this the right condition for atbegin??330 memberIter->setPosition( designators );331 return;332 } // if333 } // for334 assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );335 } else {336 assertf( false, "3 bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() );337 } // if338 } // if339 }340 341 virtual MemberIterator & smallStep() {342 PRINT( std::cerr << "smallStep in " << kind << std::endl; )343 atbegin = false;344 if ( memberIter ) {345 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )346 memberIter->smallStep();347 if ( *memberIter ) {348 PRINT( std::cerr << "success!" << std::endl; )349 return *this;350 }351 }352 return bigStep();353 }354 355 virtual Type * getType() { return inst; }356 virtual Type * getNext() {357 if ( memberIter && *memberIter ) return memberIter->getType(); // xxx - ??? recursive call???358 return nullptr;359 }360 361 virtual std::list<InitAlternative> first() const {362 std::list<InitAlternative> ret;363 PRINT( std::cerr << "first " << kind << std::endl; )364 if ( memberIter && *memberIter ) { // might not need *memberIter??365 PRINT( std::cerr << "adding children" << std::endl; )366 ret = memberIter->first();367 for ( InitAlternative & alt : ret ) {368 PRINT( std::cerr << "iterating and adding designators" << std::endl; )369 alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );370 }371 }372 if ( atbegin ) {373 // xxx - what about case of empty struct??374 // only add self if at the very beginning of the structure375 PRINT( std::cerr << "adding self" << std::endl; )376 ret.push_front( { inst->clone(), new Designation( {} ) } );377 }378 return ret;379 }380 381 virtual void print( std::ostream & out, Indenter indent ) const {382 out << kind << "(" << name << ")";383 if ( memberIter ) {384 Indenter childIndent = indent+1;385 out << std::endl << childIndent;386 memberIter->print( out, childIndent );387 }388 }389 };390 391 class UnionIterator : public AggregateIterator {392 public:393 UnionIterator( UnionInstType * inst ) : AggregateIterator( "UnionIterator", inst->get_name(), inst, inst->get_baseUnion()->get_members() ) {}394 395 virtual operator bool() const { return (memberIter && *memberIter); }396 virtual MemberIterator & bigStep() {397 // unions only initialize one member398 PRINT( std::cerr << "bigStep in " << kind << std::endl; )399 atbegin = false;400 delete memberIter;401 memberIter = nullptr;402 curType = nullptr;403 curMember = members.end();404 return *this;405 }406 };407 408 class StructIterator : public AggregateIterator {409 public:410 StructIterator( StructInstType * inst ) : AggregateIterator( "StructIterator", inst->get_name(), inst, inst->get_baseStruct()->get_members() ) {}411 412 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }413 414 virtual MemberIterator & bigStep() {415 PRINT( std::cerr << "bigStep in " << kind << std::endl; )416 atbegin = false;417 delete memberIter;418 memberIter = nullptr;419 curType = nullptr;420 for ( ; curMember != members.end(); ) {421 ++curMember;422 if ( init() ) {423 return *this;424 }425 }426 return *this;427 }428 };429 430 class TupleIterator : public AggregateIterator {431 public:432 TupleIterator( TupleType * inst ) : AggregateIterator( "TupleIterator", toString("Tuple", inst->size()), inst, inst->get_members() ) {}433 434 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }435 436 virtual MemberIterator & bigStep() {437 PRINT( std::cerr << "bigStep in " << kind << std::endl; )438 atbegin = false;439 delete memberIter;440 memberIter = nullptr;441 curType = nullptr;442 for ( ; curMember != members.end(); ) {443 ++curMember;444 if ( init() ) {445 return *this;446 }447 }448 return *this;449 }450 };451 452 MemberIterator * createMemberIterator( Type * type ) {453 if ( ReferenceToType * aggr = dynamic_cast< ReferenceToType * >( type ) ) {454 if ( StructInstType * sit = dynamic_cast< StructInstType * >( aggr ) ) {455 return new StructIterator( sit );456 } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( aggr ) ) {457 return new UnionIterator( uit );458 } else {459 assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() );460 return new SimpleIterator( type );461 }462 } else if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {463 return new ArrayIterator( at );464 } else if ( TupleType * tt = dynamic_cast< TupleType * >( type ) ) {465 return new TupleIterator( tt );466 } else {467 return new SimpleIterator( type );468 }469 }470 471 CurrentObject::CurrentObject() {}472 CurrentObject::CurrentObject( Type * type ) {473 objStack.push( new SimpleIterator( type ) );474 }475 476 477 void CurrentObject::setNext( Designation * designation ) {478 assertf( ! objStack.empty(), "obj stack empty in setNext" );479 PRINT( std::cerr << "____setNext" << designation << std::endl; )480 objStack.top()->setPosition( designation->get_designators() );481 }482 483 Designation * CurrentObject::findNext( Designation * designation ) {484 typedef std::list< Expression * > DesignatorChain;485 PRINT( std::cerr << "___findNext" << std::endl; )486 // find all the d's487 std::list<DesignatorChain> desigAlts{ { } }, newDesigAlts;488 std::list<Type *> curTypes { (objStack.top())->getType() }, newTypes;489 for ( Expression * expr : designation->get_designators() ) {490 PRINT( std::cerr << "____untyped: " << expr << std::endl; )491 std::list<DesignatorChain>::iterator dit = desigAlts.begin();492 if ( NameExpr * nexpr = dynamic_cast<NameExpr *>(expr) ) {493 for ( Type * t : curTypes ) {494 assert( dit != desigAlts.end() );495 DesignatorChain & d = *dit;496 PRINT( std::cerr << "____actual: " << t << std::endl; )497 ReferenceToType * refType = dynamic_cast<ReferenceToType *>(t);498 std::list<Declaration *> members;499 if ( refType ) {500 refType->lookup( nexpr->get_name(), members ); // concatenate identical field name501 // xxx - need to also include anonymous members in this somehow...502 for ( Declaration * mem: members ) {503 if ( ObjectDecl * field = dynamic_cast<ObjectDecl *>(mem) ) {504 PRINT( std::cerr << "____alt: " << field->get_type() << std::endl; )505 DesignatorChain newD = d;506 newD.push_back( new VariableExpr( field ) );507 newDesigAlts.push_back( newD );508 newTypes.push_back( field->get_type() );509 } // if510 } // for511 } // if512 ++dit;513 } // for514 } else {515 for ( Type * t : curTypes ) {516 assert( dit != desigAlts.end() );517 DesignatorChain & d = *dit;518 if ( ArrayType * at = dynamic_cast< ArrayType * > ( t ) ) {519 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )520 d.push_back( expr );521 newDesigAlts.push_back( d );522 newTypes.push_back( at->get_base() );523 }524 ++dit;525 } // for526 } // if527 desigAlts = newDesigAlts;528 newDesigAlts.clear();529 curTypes = newTypes;530 newTypes.clear();531 assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );532 } // for533 if ( desigAlts.size() > 1 ) {534 SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );535 } else if ( desigAlts.size() == 0 ) {536 SemanticError( designation, "No reasonable alternatives for designation: " );537 }538 DesignatorChain & d = desigAlts.back();539 PRINT( for ( Expression * expr : d ) {540 std::cerr << "____desig: " << expr << std::endl;541 } ) // for542 assertf( ! curTypes.empty(), "empty designator chosen");543 544 // set new designators545 assertf( ! objStack.empty(), "empty object stack when setting designation" );546 Designation * actualDesignation = new Designation( d );547 objStack.top()->setPosition( d ); // destroys d548 return actualDesignation;549 }550 551 void CurrentObject::increment() {552 PRINT( std::cerr << "____increment" << std::endl; )553 if ( ! objStack.empty() ) {554 PRINT( std::cerr << *objStack.top() << std::endl; )555 objStack.top()->smallStep();556 }557 }558 559 void CurrentObject::enterListInit() {560 PRINT( std::cerr << "____entering list init" << std::endl; )561 assertf( ! objStack.empty(), "empty obj stack entering list init" );562 Type * type = objStack.top()->getNext();563 if ( type ) {564 objStack.push( createMemberIterator( type ) );565 } else {566 assertf( false, "not sure about this case..." );567 }568 }569 570 void CurrentObject::exitListInit() {571 PRINT( std::cerr << "____exiting list init" << std::endl; )572 assertf( ! objStack.empty(), "objstack empty" );573 delete objStack.top();574 objStack.pop();575 if ( ! objStack.empty() ) {576 PRINT( std::cerr << *objStack.top() << std::endl; )577 objStack.top()->bigStep();578 }579 }580 581 std::list< InitAlternative > CurrentObject::getOptions() {582 PRINT( std::cerr << "____getting current options" << std::endl; )583 assertf( ! objStack.empty(), "objstack empty in getOptions" );584 return **objStack.top();585 }586 587 Type * CurrentObject::getCurrentType() {588 PRINT( std::cerr << "____getting current type" << std::endl; )589 assertf( ! objStack.empty(), "objstack empty in getCurrentType" );590 return objStack.top()->getNext();591 }592 } // namespace ResolvExpr593 41 594 42 namespace ast { -
src/ResolvExpr/FindOpenVars.cc
r790d835 rc6b4432 16 16 #include "FindOpenVars.h" 17 17 18 #include <list> // for _List_const_iterator, list<>::const...19 #include <map> // for map<>::mapped_type20 21 18 #include "AST/Pass.hpp" 22 19 #include "AST/Type.hpp" 23 20 #include "AST/TypeEnvironment.hpp" 24 #include "Common/PassVisitor.h"25 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType (ptr ...26 #include "SynTree/Type.h" // for Type, Type::ForallList, ArrayType27 21 28 22 #include <iostream> 29 23 30 24 namespace ResolvExpr { 31 struct FindOpenVars_old : public WithGuards {32 FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );33 34 void previsit( const PointerType * pointerType );35 void previsit( const ArrayType * arrayType );36 void previsit( const FunctionType * functionType );37 void previsit( const TupleType * tupleType );38 39 void common_action( const Type *type );40 41 OpenVarSet &openVars, &closedVars;42 AssertionSet &needAssertions, &haveAssertions;43 bool nextIsOpen;44 };45 46 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {47 PassVisitor<FindOpenVars_old> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );48 type->accept( finder );49 }50 51 FindOpenVars_old::FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen )52 : openVars( openVars ), closedVars( closedVars ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), nextIsOpen( firstIsOpen ) {53 }54 55 void FindOpenVars_old::common_action( const Type * type ) {56 if ( nextIsOpen ) {57 for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {58 openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };59 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {60 needAssertions[ *assert ].isUsed = false;61 }62 /// cloneAll( (*i)->get_assertions(), needAssertions );63 /// needAssertions.insert( needAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );64 }65 } else {66 for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {67 closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };68 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {69 haveAssertions[ *assert ].isUsed = false;70 }71 /// cloneAll( (*i)->get_assertions(), haveAssertions );72 /// haveAssertions.insert( haveAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );73 } // for74 } // if75 /// std::cerr << "type is ";76 /// type->print( std::cerr );77 /// std::cerr << std::endl << "need is" << std::endl;78 /// printAssertionSet( needAssertions, std::cerr );79 /// std::cerr << std::endl << "have is" << std::endl;80 /// printAssertionSet( haveAssertions, std::cerr );81 }82 83 void FindOpenVars_old::previsit(const PointerType * pointerType) {84 common_action( pointerType );85 }86 87 void FindOpenVars_old::previsit(const ArrayType * arrayType) {88 common_action( arrayType );89 }90 91 void FindOpenVars_old::previsit(const FunctionType * functionType) {92 common_action( functionType );93 nextIsOpen = ! nextIsOpen;94 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );95 }96 97 void FindOpenVars_old::previsit(const TupleType * tupleType) {98 common_action( tupleType );99 }100 25 101 26 namespace { -
src/ResolvExpr/FindOpenVars.h
r790d835 rc6b4432 17 17 18 18 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 19 #include "ResolvExpr/TypeEnvironment.h" // for AssertionSet, OpenVarSet20 19 21 class Type;22 20 namespace ast { 23 21 class Type; … … 25 23 26 24 namespace ResolvExpr { 27 // Updates open and closed variables and their associated assertions28 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );29 30 25 enum FirstMode { FirstClosed, FirstOpen }; 31 26 -
src/ResolvExpr/PolyCost.cc
r790d835 rc6b4432 18 18 #include "AST/Type.hpp" 19 19 #include "AST/TypeEnvironment.hpp" 20 #include "Common/PassVisitor.h"21 #include "SymTab/Indexer.h" // for Indexer22 #include "SynTree/Type.h" // for TypeInstType, Type23 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment24 20 25 21 namespace ResolvExpr { 26 struct PolyCost {27 PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer );28 29 void previsit( TypeInstType * aggregateUseType );30 int result;31 const TypeEnvironment &tenv;32 const SymTab::Indexer &indexer;33 };34 35 int polyCost( Type *type, const TypeEnvironment & env, const SymTab::Indexer &indexer ) {36 PassVisitor<PolyCost> coster( env, indexer );37 type->accept( coster );38 return (coster.pass.result > 0) ? 1 : 0;39 }40 41 PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), tenv( env ), indexer( indexer ) {42 }43 44 void PolyCost::previsit(TypeInstType * typeInst) {45 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) {46 if ( eqvClass->type ) {47 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) {48 if ( indexer.lookupType( otherTypeInst->name ) ) {49 // bound to opaque type50 result += 1;51 } // if52 } else {53 // bound to concrete type54 result += 1;55 } // if56 } // if57 } // if58 }59 22 60 23 // TODO: When the old PolyCost is torn out get rid of the _new suffix. -
src/ResolvExpr/PtrsAssignable.cc
r790d835 rc6b4432 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h"22 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment23 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType24 #include "SynTree/Visitor.h" // for Visitor25 26 21 27 22 namespace ResolvExpr { 28 struct PtrsAssignable : public WithShortCircuiting {29 PtrsAssignable( const Type * dest, const TypeEnvironment &env );30 31 int get_result() const { return result; }32 33 void previsit( const Type * ) { visit_children = false; }34 35 void postvisit( const VoidType * voidType );36 void postvisit( const BasicType * basicType );37 void postvisit( const PointerType * pointerType );38 void postvisit( const ArrayType * arrayType );39 void postvisit( const FunctionType * functionType );40 void postvisit( const StructInstType * inst );41 void postvisit( const UnionInstType * inst );42 void postvisit( const EnumInstType * inst );43 void postvisit( const TraitInstType * inst );44 void postvisit( const TypeInstType * inst );45 void postvisit( const TupleType * tupleType );46 void postvisit( const VarArgsType * varArgsType );47 void postvisit( const ZeroType * zeroType );48 void postvisit( const OneType * oneType );49 private:50 const Type * dest;51 int result;52 const TypeEnvironment &env;53 };54 55 int ptrsAssignable( const Type *src, const Type * dest, const TypeEnvironment &env ) {56 // std::cerr << "assignable: " << src << " | " << dest << std::endl;57 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {58 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {59 return ptrsAssignable( src, eqvClass->type, env );60 } // if61 } // if62 if ( dynamic_cast< const VoidType* >( dest ) ) {63 // void * = T * for any T is unsafe64 // xxx - this should be safe, but that currently breaks the build65 return -1;66 } else {67 PassVisitor<PtrsAssignable> ptrs( dest, env );68 src->accept( ptrs );69 return ptrs.pass.get_result();70 } // if71 }72 73 PtrsAssignable::PtrsAssignable( const Type * dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}74 75 void PtrsAssignable::postvisit( const VoidType * ) {76 // T * = void * is disallowed - this is a change from C, where any77 // void * can be assigned or passed to a non-void pointer without a cast.78 }79 80 void PtrsAssignable::postvisit( const BasicType * ) {}81 void PtrsAssignable::postvisit( const PointerType * ) {}82 void PtrsAssignable::postvisit( const ArrayType * ) {}83 void PtrsAssignable::postvisit( const FunctionType * ) {}84 85 void PtrsAssignable::postvisit( const StructInstType * ) {}86 void PtrsAssignable::postvisit( const UnionInstType * ) {}87 88 void PtrsAssignable::postvisit( const EnumInstType * ) {89 if ( dynamic_cast< const BasicType* >( dest ) ) {90 // int * = E *, etc. is safe. This isn't technically correct, as each91 // enum has one basic type that it is compatible with, an that type can92 // differ from enum to enum. Without replicating GCC's internal logic,93 // there is no way to know which type this particular enum is compatible94 // with, so punt on this for now.95 result = 1;96 }97 }98 99 void PtrsAssignable::postvisit( const TraitInstType * ) {}100 void PtrsAssignable::postvisit( const TypeInstType * inst ) {101 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {102 if ( eqvClass->type ) {103 // T * = S * for any S depends on the type bound to T104 result = ptrsAssignable( eqvClass->type, dest, env );105 }106 } // if107 }108 109 void PtrsAssignable::postvisit( const TupleType * ) {}110 void PtrsAssignable::postvisit( const VarArgsType * ) {}111 void PtrsAssignable::postvisit( const ZeroType * ) {}112 void PtrsAssignable::postvisit( const OneType * ) {}113 23 114 24 // TODO: Get rid of the `_new` suffix when the old version is removed. -
src/ResolvExpr/PtrsCastable.cc
r790d835 rc6b4432 20 20 #include "AST/Type.hpp" 21 21 #include "AST/TypeEnvironment.hpp" 22 #include "Common/PassVisitor.h"23 22 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 24 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment25 #include "SymTab/Indexer.h" // for Indexer26 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype27 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType28 #include "SynTree/Visitor.h" // for Visitor29 23 30 24 namespace ResolvExpr { 31 struct PtrsCastable_old : public WithShortCircuiting {32 public:33 PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );34 35 int get_result() const { return result; }36 37 void previsit( const Type * ) { visit_children = false; }38 39 void postvisit( const VoidType * voidType );40 void postvisit( const BasicType * basicType );41 void postvisit( const PointerType * pointerType );42 void postvisit( const ArrayType * arrayType );43 void postvisit( const FunctionType * functionType );44 void postvisit( const StructInstType * inst );45 void postvisit( const UnionInstType * inst );46 void postvisit( const EnumInstType * inst );47 void postvisit( const TraitInstType * inst );48 void postvisit( const TypeInstType * inst );49 void postvisit( const TupleType * tupleType );50 void postvisit( const VarArgsType * varArgsType );51 void postvisit( const ZeroType * zeroType );52 void postvisit( const OneType * oneType );53 private:54 const Type * dest;55 int result;56 const TypeEnvironment &env;57 const SymTab::Indexer &indexer;58 };59 60 namespace {61 int objectCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {62 if ( dynamic_cast< const FunctionType* >( src ) ) {63 return -1;64 } else if ( const TypeInstType * typeInst = dynamic_cast< const TypeInstType* >( src ) ) {65 if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->name ) ) {66 if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl* >( ntDecl ) ) {67 if ( tyDecl->kind == TypeDecl::Ftype ) {68 return -1;69 } // if70 } //if71 } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {72 if ( eqvClass->data.kind == TypeDecl::Ftype ) {73 return -1;74 } // if75 } // if76 } //if77 return 1;78 }79 int functionCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {80 return -1 * objectCast( src, env, indexer ); // reverse the sense of objectCast81 }82 }83 84 int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {85 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {86 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {87 // xxx - should this be ptrsCastable?88 return ptrsAssignable( src, eqvClass->type, env );89 } // if90 } // if91 if ( dynamic_cast< const VoidType* >( dest ) ) {92 return objectCast( src, env, indexer );93 } else {94 PassVisitor<PtrsCastable_old> ptrs( dest, env, indexer );95 src->accept( ptrs );96 return ptrs.pass.get_result();97 } // if98 }99 100 PtrsCastable_old::PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer )101 : dest( dest ), result( 0 ), env( env ), indexer( indexer ) {102 }103 104 void PtrsCastable_old::postvisit( const VoidType * ) {105 result = objectCast( dest, env, indexer );106 }107 108 void PtrsCastable_old::postvisit( const BasicType * ) {109 result = objectCast( dest, env, indexer );110 }111 112 void PtrsCastable_old::postvisit( const PointerType * ) {113 result = objectCast( dest, env, indexer );114 }115 116 void PtrsCastable_old::postvisit( const ArrayType * ) {117 result = objectCast( dest, env, indexer );118 }119 120 void PtrsCastable_old::postvisit( const FunctionType * ) {121 // result = -1;122 result = functionCast( dest, env, indexer );123 }124 125 void PtrsCastable_old::postvisit( const StructInstType * ) {126 result = objectCast( dest, env, indexer );127 }128 129 void PtrsCastable_old::postvisit( const UnionInstType * ) {130 result = objectCast( dest, env, indexer );131 }132 133 void PtrsCastable_old::postvisit( const EnumInstType * ) {134 if ( dynamic_cast< const EnumInstType * >( dest ) ) {135 result = 1;136 } else if ( const BasicType * bt = dynamic_cast< const BasicType * >( dest ) ) {137 if ( bt->kind == BasicType::SignedInt ) {138 result = 0;139 } else {140 result = 1;141 }142 } else {143 result = objectCast( dest, env, indexer );144 }145 }146 147 void PtrsCastable_old::postvisit( const TraitInstType * ) {}148 149 void PtrsCastable_old::postvisit( const TypeInstType *inst ) {150 //result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;151 result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;152 }153 154 void PtrsCastable_old::postvisit( const TupleType * ) {155 result = objectCast( dest, env, indexer );156 }157 158 void PtrsCastable_old::postvisit( const VarArgsType * ) {159 result = objectCast( dest, env, indexer );160 }161 162 void PtrsCastable_old::postvisit( const ZeroType * ) {163 result = objectCast( dest, env, indexer );164 }165 166 void PtrsCastable_old::postvisit( const OneType * ) {167 result = objectCast( dest, env, indexer );168 }169 25 170 26 namespace { -
src/ResolvExpr/RenameVars.cc
r790d835 rc6b4432 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h"24 23 #include "Common/ScopedMap.h" 25 24 #include "Common/SemanticError.h" // for SemanticError 26 25 #include "RenameVars.h" 27 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec...28 #include "SynTree/Expression.h" // for Expression29 #include "SynTree/Type.h" // for Type, TypeInstType, TraitInstType30 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept31 26 32 27 #include "AST/Copy.hpp" … … 49 44 } 50 45 51 void rename( TypeInstType * type ) {52 auto it = nameMap.find( type->name );53 if ( it != nameMap.end() ) {54 type->name = it->second;55 }56 }57 58 46 void nextUsage() { 59 47 ++next_usage_id; 60 }61 62 void openLevel( Type * type ) {63 if ( ! type->forall.empty() ) {64 nameMap.beginScope();65 // renames all "forall" type names to `_${level}_${name}'66 for ( auto td : type->forall ) {67 std::ostringstream output;68 output << "_" << resetCount << "_" << level << "_" << td->name;69 std::string newname( output.str() );70 nameMap[ td->get_name() ] = newname;71 td->name = newname;72 // ditto for assertion names, the next level in73 level++;74 }75 }76 }77 78 void closeLevel( Type * type ) {79 if ( !type->forall.empty() ) {80 nameMap.endScope();81 }82 48 } 83 49 … … 135 101 RenamingData renaming; 136 102 137 struct RenameVars_old {138 void previsit( TypeInstType * instType ) {139 renaming.openLevel( (Type*)instType );140 renaming.rename( instType );141 }142 void previsit( Type * type ) {143 renaming.openLevel( type );144 }145 void postvisit( Type * type ) {146 renaming.closeLevel( type );147 }148 };149 150 103 struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ { 151 104 RenameMode mode; … … 178 131 } // namespace 179 132 180 void renameTyVars( Type * t ) {181 PassVisitor<RenameVars_old> renamer;182 t->accept( renamer );183 }184 185 133 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) { 186 134 ast::Pass<RenameVars_new> renamer; -
src/ResolvExpr/RenameVars.h
r790d835 rc6b4432 16 16 #pragma once 17 17 18 #include <list> // for list19 #include <map> // for map20 #include <string> // for string21 22 #include "SynTree/SynTree.h" // for Visitor Nodes23 #include "SynTree/Visitor.h" // for Visitor24 25 18 namespace ast { 26 19 class Type; … … 28 21 29 22 namespace ResolvExpr { 30 /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID31 void renameTyVars( Type * );32 33 23 enum RenameMode { 34 24 GEN_USAGE, // for type in VariableExpr -
src/ResolvExpr/ResolveTypeof.cc
r790d835 rc6b4432 24 24 #include "AST/Type.hpp" 25 25 #include "AST/TypeEnvironment.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor27 26 #include "Common/utility.h" // for copy 28 27 #include "InitTweak/InitTweak.h" // for isConstExpr … … 30 29 #include "Resolver.h" // for resolveInVoidContext 31 30 #include "SymTab/Mangler.h" 32 #include "SynTree/Expression.h" // for Expression33 #include "SynTree/Mutator.h" // for Mutator34 #include "SynTree/Type.h" // for TypeofType, Type35 36 namespace SymTab {37 class Indexer;38 } // namespace SymTab39 31 40 32 namespace ResolvExpr { 41 namespace {42 #if 043 void44 printAlts( const AltList &list, std::ostream &os, int indent = 0 )45 {46 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {47 i->print( os, indent );48 os << std::endl;49 }50 }51 #endif52 }53 54 class ResolveTypeof_old : public WithShortCircuiting {55 public:56 ResolveTypeof_old( const SymTab::Indexer &indexer ) : indexer( indexer ) {}57 void premutate( TypeofType *typeofType );58 Type * postmutate( TypeofType *typeofType );59 60 private:61 const SymTab::Indexer &indexer;62 };63 64 Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {65 PassVisitor<ResolveTypeof_old> mutator( indexer );66 return type->acceptMutator( mutator );67 }68 69 void ResolveTypeof_old::premutate( TypeofType * ) {70 visit_children = false;71 }72 73 Type * ResolveTypeof_old::postmutate( TypeofType *typeofType ) {74 #if 075 std::cerr << "resolving typeof: ";76 typeofType->print( std::cerr );77 std::cerr << std::endl;78 #endif79 // pass on null expression80 if ( ! typeofType->expr ) return typeofType;81 82 bool isBasetypeof = typeofType->is_basetypeof;83 auto oldQuals = typeofType->get_qualifiers().val;84 85 Type* newType;86 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(typeofType->expr) ) {87 // typeof wrapping type88 newType = tyExpr->type;89 tyExpr->type = nullptr;90 delete tyExpr;91 } else {92 // typeof wrapping expression93 Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer );94 assert( newExpr->result && ! newExpr->result->isVoid() );95 newType = newExpr->result;96 newExpr->result = nullptr;97 delete typeofType;98 delete newExpr;99 }100 101 // clear qualifiers for base, combine with typeoftype quals in any case102 if ( isBasetypeof ) {103 // replace basetypeof(<enum>) by int104 if ( dynamic_cast<EnumInstType*>(newType) ) {105 Type* newerType =106 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,107 newType->attributes };108 delete newType;109 newType = newerType;110 }111 newType->get_qualifiers().val112 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;113 } else {114 newType->get_qualifiers().val |= oldQuals;115 }116 117 return newType;118 }119 33 120 34 namespace { -
src/ResolvExpr/Resolver.cc
r790d835 rc6b4432 19 19 #include <vector> // for vector 20 20 21 #include "Alternative.h" // for Alternative, AltList22 #include "AlternativeFinder.h" // for AlternativeFinder, resolveIn...23 21 #include "Candidate.hpp" 24 22 #include "CandidateFinder.hpp" … … 40 38 #include "Common/Eval.h" // for eval 41 39 #include "Common/Iterate.hpp" // for group_iterate 42 #include "Common/PassVisitor.h" // for PassVisitor43 40 #include "Common/SemanticError.h" // for SemanticError 44 41 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 45 42 #include "Common/ToString.hpp" // for toCString 43 #include "Common/UniqueName.h" // for UniqueName 46 44 #include "InitTweak/GenInit.h" 47 45 #include "InitTweak/InitTweak.h" // for isIntrinsicSingleArgCallStmt 48 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment49 #include "SymTab/Autogen.h" // for SizeType50 #include "SymTab/Indexer.h" // for Indexer51 46 #include "SymTab/Mangler.h" // for Mangler 52 #include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar...53 #include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr54 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit55 #include "SynTree/Statement.h" // for ForStmt, Statement, BranchStmt56 #include "SynTree/Type.h" // for Type, BasicType, PointerType57 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution58 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept59 47 #include "Tuples/Tuples.h" 60 48 #include "Validate/FindSpecialDecls.h" // for SizeType … … 63 51 64 52 namespace ResolvExpr { 65 struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {66 Resolver_old() {}67 Resolver_old( const SymTab::Indexer & other ) {68 indexer = other;69 }70 71 void previsit( FunctionDecl * functionDecl );72 void postvisit( FunctionDecl * functionDecl );73 void previsit( ObjectDecl * objectDecll );74 void previsit( EnumDecl * enumDecl );75 void previsit( StaticAssertDecl * assertDecl );76 77 void previsit( ArrayType * at );78 void previsit( PointerType * at );79 80 void previsit( ExprStmt * exprStmt );81 void previsit( AsmExpr * asmExpr );82 void previsit( AsmStmt * asmStmt );83 void previsit( IfStmt * ifStmt );84 void previsit( WhileDoStmt * whileDoStmt );85 void previsit( ForStmt * forStmt );86 void previsit( SwitchStmt * switchStmt );87 void previsit( CaseStmt * caseStmt );88 void previsit( BranchStmt * branchStmt );89 void previsit( ReturnStmt * returnStmt );90 void previsit( ThrowStmt * throwStmt );91 void previsit( CatchStmt * catchStmt );92 void postvisit( CatchStmt * catchStmt );93 void previsit( WaitForStmt * stmt );94 95 void previsit( SingleInit * singleInit );96 void previsit( ListInit * listInit );97 void previsit( ConstructorInit * ctorInit );98 private:99 typedef std::list< Initializer * >::iterator InitIterator;100 101 template< typename PtrType >102 void handlePtrType( PtrType * type );103 104 void fallbackInit( ConstructorInit * ctorInit );105 106 Type * functionReturn = nullptr;107 CurrentObject currentObject = nullptr;108 bool inEnumDecl = false;109 };110 111 struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {112 void previsit( FunctionDecl * );113 void previsit( WithStmt * );114 115 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );116 };117 118 void resolve( std::list< Declaration * > translationUnit ) {119 PassVisitor<Resolver_old> resolver;120 acceptAll( translationUnit, resolver );121 }122 123 void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {124 PassVisitor<Resolver_old> resolver( indexer );125 maybeAccept( decl, resolver );126 }127 128 namespace {129 struct DeleteFinder_old : public WithShortCircuiting {130 DeletedExpr * delExpr = nullptr;131 void previsit( DeletedExpr * expr ) {132 if ( delExpr ) visit_children = false;133 else delExpr = expr;134 }135 136 void previsit( Expression * ) {137 if ( delExpr ) visit_children = false;138 }139 };140 }141 142 DeletedExpr * findDeletedExpr( Expression * expr ) {143 PassVisitor<DeleteFinder_old> finder;144 expr->accept( finder );145 return finder.pass.delExpr;146 }147 148 namespace {149 struct StripCasts_old {150 Expression * postmutate( CastExpr * castExpr ) {151 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {152 // generated cast is to the same type as its argument, so it's unnecessary -- remove it153 Expression * expr = castExpr->arg;154 castExpr->arg = nullptr;155 std::swap( expr->env, castExpr->env );156 return expr;157 }158 return castExpr;159 }160 161 static void strip( Expression *& expr ) {162 PassVisitor<StripCasts_old> stripper;163 expr = expr->acceptMutator( stripper );164 }165 };166 167 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {168 expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;169 env.makeSubstitution( *expr->env );170 StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression171 }172 173 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {174 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {175 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {176 // cast is to the same type as its argument, so it's unnecessary -- remove it177 expr = castExpr->arg;178 castExpr->arg = nullptr;179 std::swap( expr->env, castExpr->env );180 delete castExpr;181 }182 }183 }184 } // namespace185 186 namespace {187 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {188 assertf( untyped, "expected a non-null expression." );189 190 // xxx - this isn't thread-safe, but should work until we parallelize the resolver191 static unsigned recursion_level = 0;192 193 ++recursion_level;194 TypeEnvironment env;195 AlternativeFinder finder( indexer, env );196 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );197 --recursion_level;198 199 #if 0200 if ( finder.get_alternatives().size() != 1 ) {201 std::cerr << "untyped expr is ";202 untyped->print( std::cerr );203 std::cerr << std::endl << "alternatives are:";204 for ( const Alternative & alt : finder.get_alternatives() ) {205 alt.print( std::cerr );206 } // for207 } // if208 #endif209 210 // produce filtered list of alternatives211 AltList candidates;212 for ( Alternative & alt : finder.get_alternatives() ) {213 if ( pred( alt ) ) {214 candidates.push_back( std::move( alt ) );215 }216 }217 218 // produce invalid error if no candidates219 if ( candidates.empty() ) {220 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );221 }222 223 // search for cheapest candidate224 AltList winners;225 bool seen_undeleted = false;226 for ( unsigned i = 0; i < candidates.size(); ++i ) {227 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );228 229 if ( c > 0 ) continue; // skip more expensive than winner230 231 if ( c < 0 ) {232 // reset on new cheapest233 seen_undeleted = ! findDeletedExpr( candidates[i].expr );234 winners.clear();235 } else /* if ( c == 0 ) */ {236 if ( findDeletedExpr( candidates[i].expr ) ) {237 // skip deleted expression if already seen one equivalent-cost not238 if ( seen_undeleted ) continue;239 } else if ( ! seen_undeleted ) {240 // replace list of equivalent-cost deleted expressions with one non-deleted241 winners.clear();242 seen_undeleted = true;243 }244 }245 246 winners.emplace_back( std::move( candidates[i] ) );247 }248 249 // promote alternative.cvtCost to .cost250 // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost251 for ( Alternative& winner : winners ) {252 winner.cost = winner.cvtCost;253 }254 255 // produce ambiguous errors, if applicable256 if ( winners.size() != 1 ) {257 std::ostringstream stream;258 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";259 untyped->print( stream );260 stream << " Alternatives are:\n";261 printAlts( winners, stream, 1 );262 SemanticError( untyped->location, stream.str() );263 }264 265 // single selected choice266 Alternative& choice = winners.front();267 268 // fail on only expression deleted269 if ( ! seen_undeleted ) {270 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );271 }272 273 // xxx - check for ambiguous expressions274 275 // output selected choice276 alt = std::move( choice );277 }278 279 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages280 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {281 if ( ! untyped ) return;282 Alternative choice;283 findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );284 finishExpr( choice.expr, choice.env, untyped->env );285 delete untyped;286 untyped = choice.expr;287 choice.expr = nullptr;288 }289 290 bool standardAlternativeFilter( const Alternative & ) {291 // currently don't need to filter, under normal circumstances.292 // in the future, this may be useful for removing deleted expressions293 return true;294 }295 } // namespace296 297 // used in resolveTypeof298 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {299 TypeEnvironment env;300 return resolveInVoidContext( expr, indexer, env );301 }302 303 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {304 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0305 // interpretations, an exception has already been thrown.306 assertf( expr, "expected a non-null expression." );307 308 CastExpr * untyped = new CastExpr( expr ); // cast to void309 untyped->location = expr->location;310 311 // set up and resolve expression cast to void312 Alternative choice;313 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );314 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );315 assert( castExpr );316 env = std::move( choice.env );317 318 // clean up resolved expression319 Expression * ret = castExpr->arg;320 castExpr->arg = nullptr;321 322 // unlink the arg so that it isn't deleted twice at the end of the program323 untyped->arg = nullptr;324 return ret;325 }326 327 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {328 resetTyVarRenaming();329 TypeEnvironment env;330 Expression * newExpr = resolveInVoidContext( untyped, indexer, env );331 finishExpr( newExpr, env, untyped->env );332 delete untyped;333 untyped = newExpr;334 }335 336 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {337 findKindExpression( untyped, indexer, "", standardAlternativeFilter );338 }339 340 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) {341 assert( untyped && type );342 // transfer location to generated cast for error purposes343 CodeLocation location = untyped->location;344 untyped = new CastExpr( untyped, type );345 untyped->location = location;346 findSingleExpression( untyped, indexer );347 removeExtraneousCast( untyped, indexer );348 }349 350 namespace {351 bool isIntegralType( const Alternative & alt ) {352 Type * type = alt.expr->result;353 if ( dynamic_cast< EnumInstType * >( type ) ) {354 return true;355 } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {356 return bt->isInteger();357 } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {358 return true;359 } else {360 return false;361 } // if362 }363 364 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {365 findKindExpression( untyped, indexer, "condition", isIntegralType );366 }367 }368 369 370 bool isStructOrUnion( const Alternative & alt ) {371 Type * t = alt.expr->result->stripReferences();372 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );373 }374 375 void resolveWithExprs( std::list< Declaration * > & translationUnit ) {376 PassVisitor<ResolveWithExprs> resolver;377 acceptAll( translationUnit, resolver );378 }379 380 void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {381 for ( Expression *& expr : withExprs ) {382 // only struct- and union-typed expressions are viable candidates383 findKindExpression( expr, indexer, "with statement", isStructOrUnion );384 385 // if with expression might be impure, create a temporary so that it is evaluated once386 if ( Tuples::maybeImpure( expr ) ) {387 static UniqueName tmpNamer( "_with_tmp_" );388 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );389 expr = new VariableExpr( tmp );390 newStmts.push_back( new DeclStmt( tmp ) );391 if ( InitTweak::isConstructable( tmp->type ) ) {392 // generate ctor/dtor and resolve them393 tmp->init = InitTweak::genCtorInit( tmp );394 tmp->accept( *visitor );395 }396 }397 }398 }399 400 void ResolveWithExprs::previsit( WithStmt * withStmt ) {401 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );402 }403 404 void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {405 {406 // resolve with-exprs with parameters in scope and add any newly generated declarations to the407 // front of the function body.408 auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } );409 indexer.addFunctionType( functionDecl->type );410 std::list< Statement * > newStmts;411 resolveWithExprs( functionDecl->withExprs, newStmts );412 if ( functionDecl->statements ) {413 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts );414 } else {415 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() );416 }417 }418 }419 420 void Resolver_old::previsit( ObjectDecl * objectDecl ) {421 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that422 // class-variable initContext is changed multiple time because the LHS is analysed twice.423 // The second analysis changes initContext because of a function type can contain object424 // declarations in the return and parameter types. So each value of initContext is425 // retained, so the type on the first analysis is preserved and used for selecting the RHS.426 GuardValue( currentObject );427 currentObject = CurrentObject( objectDecl->get_type() );428 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {429 // enumerator initializers should not use the enum type to initialize, since430 // the enum type is still incomplete at this point. Use signed int instead.431 // TODO: BasicType::SignedInt may not longer be true432 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );433 }434 }435 436 template< typename PtrType >437 void Resolver_old::handlePtrType( PtrType * type ) {438 if ( type->get_dimension() ) {439 findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );440 }441 }442 443 void Resolver_old::previsit( ArrayType * at ) {444 handlePtrType( at );445 }446 447 void Resolver_old::previsit( PointerType * pt ) {448 handlePtrType( pt );449 }450 451 void Resolver_old::previsit( FunctionDecl * functionDecl ) {452 #if 0453 std::cerr << "resolver visiting functiondecl ";454 functionDecl->print( std::cerr );455 std::cerr << std::endl;456 #endif457 GuardValue( functionReturn );458 functionReturn = ResolvExpr::extractResultType( functionDecl->type );459 }460 461 void Resolver_old::postvisit( FunctionDecl * functionDecl ) {462 // default value expressions have an environment which shouldn't be there and trips up463 // later passes.464 // xxx - it might be necessary to somehow keep the information from this environment, but I465 // can't currently see how it's useful.466 for ( Declaration * d : functionDecl->type->parameters ) {467 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {468 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) {469 delete init->value->env;470 init->value->env = nullptr;471 }472 }473 }474 }475 476 void Resolver_old::previsit( EnumDecl * ) {477 // in case we decide to allow nested enums478 GuardValue( inEnumDecl );479 inEnumDecl = true;480 }481 482 void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {483 findIntegralExpression( assertDecl->condition, indexer );484 }485 486 void Resolver_old::previsit( ExprStmt * exprStmt ) {487 visit_children = false;488 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );489 findVoidExpression( exprStmt->expr, indexer );490 }491 492 void Resolver_old::previsit( AsmExpr * asmExpr ) {493 visit_children = false;494 findVoidExpression( asmExpr->operand, indexer );495 }496 497 void Resolver_old::previsit( AsmStmt * asmStmt ) {498 visit_children = false;499 acceptAll( asmStmt->get_input(), *visitor );500 acceptAll( asmStmt->get_output(), *visitor );501 }502 503 void Resolver_old::previsit( IfStmt * ifStmt ) {504 findIntegralExpression( ifStmt->condition, indexer );505 }506 507 void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) {508 findIntegralExpression( whileDoStmt->condition, indexer );509 }510 511 void Resolver_old::previsit( ForStmt * forStmt ) {512 if ( forStmt->condition ) {513 findIntegralExpression( forStmt->condition, indexer );514 } // if515 516 if ( forStmt->increment ) {517 findVoidExpression( forStmt->increment, indexer );518 } // if519 }520 521 void Resolver_old::previsit( SwitchStmt * switchStmt ) {522 GuardValue( currentObject );523 findIntegralExpression( switchStmt->condition, indexer );524 525 currentObject = CurrentObject( switchStmt->condition->result );526 }527 528 void Resolver_old::previsit( CaseStmt * caseStmt ) {529 if ( caseStmt->condition ) {530 std::list< InitAlternative > initAlts = currentObject.getOptions();531 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );532 // must remove cast from case statement because RangeExpr cannot be cast.533 Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );534 findSingleExpression( newExpr, indexer );535 // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.536 // Ideally we would perform the conversion internally here.537 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {538 newExpr = castExpr->arg;539 castExpr->arg = nullptr;540 std::swap( newExpr->env, castExpr->env );541 delete castExpr;542 }543 caseStmt->condition = newExpr;544 }545 }546 547 void Resolver_old::previsit( BranchStmt * branchStmt ) {548 visit_children = false;549 // must resolve the argument for a computed goto550 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement551 if ( branchStmt->computedTarget ) {552 // computed goto argument is void *553 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );554 } // if555 } // if556 }557 558 void Resolver_old::previsit( ReturnStmt * returnStmt ) {559 visit_children = false;560 if ( returnStmt->expr ) {561 findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );562 } // if563 }564 565 void Resolver_old::previsit( ThrowStmt * throwStmt ) {566 visit_children = false;567 // TODO: Replace *exception type with &exception type.568 if ( throwStmt->get_expr() ) {569 const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );570 assert( exception_decl );571 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );572 findSingleExpression( throwStmt->expr, exceptType, indexer );573 }574 }575 576 void Resolver_old::previsit( CatchStmt * catchStmt ) {577 // Until we are very sure this invarent (ifs that move between passes have then)578 // holds, check it. This allows a check for when to decode the mangling.579 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {580 assert( ifStmt->then );581 }582 // Encode the catchStmt so the condition can see the declaration.583 if ( catchStmt->cond ) {584 IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );585 catchStmt->cond = nullptr;586 catchStmt->body = ifStmt;587 }588 }589 590 void Resolver_old::postvisit( CatchStmt * catchStmt ) {591 // Decode the catchStmt so everything is stored properly.592 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );593 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {594 assert( ifStmt->condition );595 assert( ifStmt->else_ );596 catchStmt->cond = ifStmt->condition;597 catchStmt->body = ifStmt->else_;598 ifStmt->condition = nullptr;599 ifStmt->else_ = nullptr;600 delete ifStmt;601 }602 }603 604 53 template< typename iterator_t > 605 54 inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) { … … 610 59 return it != end; 611 60 } 612 613 void Resolver_old::previsit( WaitForStmt * stmt ) {614 visit_children = false;615 616 // Resolve all clauses first617 for( auto& clause : stmt->clauses ) {618 619 TypeEnvironment env;620 AlternativeFinder funcFinder( indexer, env );621 622 // Find all alternatives for a function in canonical form623 funcFinder.findWithAdjustment( clause.target.function );624 625 if ( funcFinder.get_alternatives().empty() ) {626 stringstream ss;627 ss << "Use of undeclared indentifier '";628 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name;629 ss << "' in call to waitfor";630 SemanticError( stmt->location, ss.str() );631 }632 633 if(clause.target.arguments.empty()) {634 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter");635 }636 637 // Find all alternatives for all arguments in canonical form638 std::vector< AlternativeFinder > argAlternatives;639 funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );640 641 // List all combinations of arguments642 std::vector< AltList > possibilities;643 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );644 645 AltList func_candidates;646 std::vector< AltList > args_candidates;647 648 // For every possible function :649 // try matching the arguments to the parameters650 // not the other way around because we have more arguments than parameters651 SemanticErrorException errors;652 for ( Alternative & func : funcFinder.get_alternatives() ) {653 try {654 PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() );655 if( !pointer ) {656 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" );657 }658 659 FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() );660 if( !function ) {661 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" );662 }663 664 665 {666 auto param = function->parameters.begin();667 auto param_end = function->parameters.end();668 669 if( !advance_to_mutex( param, param_end ) ) {670 SemanticError(function, "candidate function not viable: no mutex parameters\n");671 }672 }673 674 Alternative newFunc( func );675 // Strip reference from function676 referenceToRvalueConversion( newFunc.expr, newFunc.cost );677 678 // For all the set of arguments we have try to match it with the parameter of the current function alternative679 for ( auto & argsList : possibilities ) {680 681 try {682 // Declare data structures need for resolution683 OpenVarSet openVars;684 AssertionSet resultNeed, resultHave;685 TypeEnvironment resultEnv( func.env );686 makeUnifiableVars( function, openVars, resultNeed );687 // add all type variables as open variables now so that those not used in the parameter688 // list are still considered open.689 resultEnv.add( function->forall );690 691 // Load type variables from arguemnts into one shared space692 simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );693 694 // Make sure we don't widen any existing bindings695 resultEnv.forbidWidening();696 697 // Find any unbound type variables698 resultEnv.extractOpenVars( openVars );699 700 auto param = function->parameters.begin();701 auto param_end = function->parameters.end();702 703 int n_mutex_param = 0;704 705 // For every arguments of its set, check if it matches one of the parameter706 // The order is important707 for( auto & arg : argsList ) {708 709 // Ignore non-mutex arguments710 if( !advance_to_mutex( param, param_end ) ) {711 // We ran out of parameters but still have arguments712 // this function doesn't match713 SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));714 }715 716 n_mutex_param++;717 718 // Check if the argument matches the parameter type in the current scope719 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {720 // Type doesn't match721 stringstream ss;722 ss << "candidate function not viable: no known convertion from '";723 (*param)->get_type()->print( ss );724 ss << "' to '";725 arg.expr->get_result()->print( ss );726 ss << "' with env '";727 resultEnv.print(ss);728 ss << "'\n";729 SemanticError( function, ss.str() );730 }731 732 param++;733 }734 735 // All arguments match !736 737 // Check if parameters are missing738 if( advance_to_mutex( param, param_end ) ) {739 do {740 n_mutex_param++;741 param++;742 } while( advance_to_mutex( param, param_end ) );743 744 // We ran out of arguments but still have parameters left745 // this function doesn't match746 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));747 }748 749 // All parameters match !750 751 // Finish the expressions to tie in the proper environments752 finishExpr( newFunc.expr, resultEnv );753 for( Alternative & alt : argsList ) {754 finishExpr( alt.expr, resultEnv );755 }756 757 // This is a match store it and save it for later758 func_candidates.push_back( newFunc );759 args_candidates.push_back( argsList );760 761 }762 catch( SemanticErrorException & e ) {763 errors.append( e );764 }765 }766 }767 catch( SemanticErrorException & e ) {768 errors.append( e );769 }770 }771 772 // Make sure we got the right number of arguments773 if( func_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor" ); top.append( errors ); throw top; }774 if( args_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; }775 if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor" ); top.append( errors ); throw top; }776 if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor" ); top.append( errors ); throw top; }777 // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.778 779 // Swap the results from the alternative with the unresolved values.780 // Alternatives will handle deletion on destruction781 std::swap( clause.target.function, func_candidates.front().expr );782 for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) {783 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr );784 }785 786 // Resolve the conditions as if it were an IfStmt787 // Resolve the statments normally788 findSingleExpression( clause.condition, this->indexer );789 clause.statement->accept( *visitor );790 }791 792 793 if( stmt->timeout.statement ) {794 // Resolve the timeout as an size_t for now795 // Resolve the conditions as if it were an IfStmt796 // Resolve the statments normally797 findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer );798 findSingleExpression( stmt->timeout.condition, this->indexer );799 stmt->timeout.statement->accept( *visitor );800 }801 802 if( stmt->orelse.statement ) {803 // Resolve the conditions as if it were an IfStmt804 // Resolve the statments normally805 findSingleExpression( stmt->orelse.condition, this->indexer );806 stmt->orelse.statement->accept( *visitor );807 }808 }809 810 bool isCharType( Type * t ) {811 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {812 return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||813 bt->get_kind() == BasicType::UnsignedChar;814 }815 return false;816 }817 818 void Resolver_old::previsit( SingleInit * singleInit ) {819 visit_children = false;820 // resolve initialization using the possibilities as determined by the currentObject cursor821 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() );822 findSingleExpression( newExpr, indexer );823 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr );824 825 // move cursor to the object that is actually initialized826 currentObject.setNext( initExpr->get_designation() );827 828 // discard InitExpr wrapper and retain relevant pieces829 newExpr = initExpr->expr;830 initExpr->expr = nullptr;831 std::swap( initExpr->env, newExpr->env );832 // InitExpr may have inferParams in the case where the expression specializes a function833 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not834 // sufficient.835 newExpr->spliceInferParams( initExpr );836 delete initExpr;837 838 // get the actual object's type (may not exactly match what comes back from the resolver839 // due to conversions)840 Type * initContext = currentObject.getCurrentType();841 842 removeExtraneousCast( newExpr, indexer );843 844 // check if actual object's type is char[]845 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {846 if ( isCharType( at->get_base() ) ) {847 // check if the resolved type is char *848 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {849 if ( isCharType( pt->get_base() ) ) {850 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {851 // strip cast if we're initializing a char[] with a char *,852 // e.g. char x[] = "hello";853 newExpr = ce->get_arg();854 ce->set_arg( nullptr );855 std::swap( ce->env, newExpr->env );856 delete ce;857 }858 }859 }860 }861 }862 863 // set initializer expr to resolved express864 singleInit->value = newExpr;865 866 // move cursor to next object in preparation for next initializer867 currentObject.increment();868 }869 870 void Resolver_old::previsit( ListInit * listInit ) {871 visit_children = false;872 // move cursor into brace-enclosed initializer-list873 currentObject.enterListInit();874 // xxx - fix this so that the list isn't copied, iterator should be used to change current875 // element876 std::list<Designation *> newDesignations;877 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {878 // iterate designations and initializers in pairs, moving the cursor to the current879 // designated object and resolving the initializer against that object.880 Designation * des = std::get<0>(p);881 Initializer * init = std::get<1>(p);882 newDesignations.push_back( currentObject.findNext( des ) );883 init->accept( *visitor );884 }885 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list886 listInit->get_designations() = newDesignations; // xxx - memory management887 currentObject.exitListInit();888 889 // xxx - this part has not be folded into CurrentObject yet890 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {891 // Type * base = tt->get_baseType()->get_base();892 // if ( base ) {893 // // know the implementation type, so try using that as the initContext894 // ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr );895 // currentObject = &tmpObj;896 // visit( listInit );897 // } else {898 // // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context899 // Parent::visit( listInit );900 // }901 // } else {902 }903 904 // ConstructorInit - fall back on C-style initializer905 void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {906 // could not find valid constructor, or found an intrinsic constructor907 // fall back on C-style initializer908 delete ctorInit->get_ctor();909 ctorInit->set_ctor( nullptr );910 delete ctorInit->get_dtor();911 ctorInit->set_dtor( nullptr );912 maybeAccept( ctorInit->get_init(), *visitor );913 }914 915 // needs to be callable from outside the resolver, so this is a standalone function916 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {917 assert( ctorInit );918 PassVisitor<Resolver_old> resolver( indexer );919 ctorInit->accept( resolver );920 }921 922 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {923 assert( stmtExpr );924 PassVisitor<Resolver_old> resolver( indexer );925 stmtExpr->accept( resolver );926 stmtExpr->computeResult();927 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead?928 }929 930 void Resolver_old::previsit( ConstructorInit * ctorInit ) {931 visit_children = false;932 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit933 maybeAccept( ctorInit->ctor, *visitor );934 maybeAccept( ctorInit->dtor, *visitor );935 936 // found a constructor - can get rid of C-style initializer937 delete ctorInit->init;938 ctorInit->init = nullptr;939 940 // intrinsic single parameter constructors and destructors do nothing. Since this was941 // implicitly generated, there's no way for it to have side effects, so get rid of it942 // to clean up generated code.943 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {944 delete ctorInit->ctor;945 ctorInit->ctor = nullptr;946 }947 948 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {949 delete ctorInit->dtor;950 ctorInit->dtor = nullptr;951 }952 953 // xxx - todo -- what about arrays?954 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {955 // // can reduce the constructor down to a SingleInit using the956 // // second argument from the ctor call, since957 // delete ctorInit->get_ctor();958 // ctorInit->set_ctor( nullptr );959 960 // Expression * arg =961 // ctorInit->set_init( new SingleInit( arg ) );962 // }963 }964 965 ///////////////////////////////////////////////////////////////////////////966 //967 // *** NEW RESOLVER ***968 //969 ///////////////////////////////////////////////////////////////////////////970 61 971 62 namespace { -
src/ResolvExpr/SatisfyAssertions.cpp
r790d835 rc6b4432 46 46 #include "SymTab/Mangler.h" 47 47 48 49 50 48 namespace ResolvExpr { 51 49 -
src/ResolvExpr/SpecCost.cc
r790d835 rc6b4432 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h"24 #include "SynTree/Declaration.h"25 #include "SynTree/Expression.h"26 #include "SynTree/Type.h"27 23 28 24 namespace ResolvExpr { 29 30 /// Counts specializations in a type31 class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> {32 int count = -1; ///< specialization count (-1 for none)33 34 public:35 int get_count() const { return count >= 0 ? count : 0; }36 37 // mark specialization of base type38 void postvisit(PointerType*) { if ( count >= 0 ) ++count; }39 40 // mark specialization of base type41 void postvisit(ArrayType*) { if ( count >= 0 ) ++count; }42 43 // mark specialization of base type44 void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; }45 46 void postvisit(StructInstType*) { if ( count >= 0 ) ++count; }47 void postvisit(UnionInstType*) { if ( count >= 0 ) ++count; }48 49 private:50 // takes minimum non-negative count over parameter/return list51 void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {52 for ( DeclarationWithType* dwt : dwts ) {53 count = -1;54 maybeAccept( dwt->get_type(), *visitor );55 if ( count != -1 && count < mincount ) mincount = count;56 }57 }58 59 public:60 // take minimal specialization value over ->returnVals and ->parameters61 void previsit(FunctionType* fty) {62 int mincount = std::numeric_limits<int>::max();63 takeminover( mincount, fty->parameters );64 takeminover( mincount, fty->returnVals );65 // add another level to mincount if set66 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;67 // already visited children68 visit_children = false;69 }70 71 private:72 // returns minimum non-negative count + 1 over type parameters (-1 if none such)73 int minover( std::list<Expression*>& parms ) {74 int mincount = std::numeric_limits<int>::max();75 for ( Expression* parm : parms ) {76 count = -1;77 maybeAccept( parm->result, *visitor );78 if ( count != -1 && count < mincount ) mincount = count;79 }80 return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;81 }82 83 public:84 // look for polymorphic parameters85 void previsit(StructInstType* sty) {86 count = minover( sty->parameters );87 }88 89 // look for polymorphic parameters90 void previsit(UnionInstType* uty) {91 count = minover( uty->parameters );92 }93 94 // note polymorphic type (which may be specialized)95 // xxx - maybe account for open/closed type variables96 void postvisit(TypeInstType*) { count = 0; }97 98 // take minimal specialization over elements99 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize100 void previsit(TupleType* tty) {101 int mincount = std::numeric_limits<int>::max();102 for ( Type* ty : tty->types ) {103 count = -1;104 maybeAccept( ty, *visitor );105 if ( count != -1 && count < mincount ) mincount = count;106 }107 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;108 visit_children = false;109 }110 };111 112 /// Returns the (negated) specialization cost for a given type113 int specCost( Type* ty ) {114 PassVisitor<CountSpecs> counter;115 maybeAccept( ty, *counter.pass.visitor );116 return counter.pass.get_count();117 }118 25 119 26 namespace { -
src/ResolvExpr/Unify.cc
r790d835 rc6b4432 33 33 #include "AST/TypeEnvironment.hpp" 34 34 #include "Common/Eval.h" // for eval 35 #include "Common/PassVisitor.h" // for PassVisitor36 35 #include "CommonType.hpp" // for commonType 37 36 #include "FindOpenVars.h" // for findOpenVars 38 37 #include "SpecCost.hpp" // for SpecCost 39 #include "SynTree/LinkageSpec.h" // for C40 #include "SynTree/Constant.h" // for Constant41 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Declarati...42 #include "SynTree/Expression.h" // for TypeExpr, Expression, ConstantExpr43 #include "SynTree/Mutator.h" // for Mutator44 #include "SynTree/Type.h" // for Type, TypeInstType, FunctionType45 #include "SynTree/Visitor.h" // for Visitor46 38 #include "Tuples/Tuples.h" // for isTtype 47 #include "TypeEnvironment.h" // for EqvClass, AssertionSet, OpenVarSet48 39 #include "typeops.h" // for flatten, occurs 49 40 … … 52 43 } 53 44 54 namespace SymTab {55 class Indexer;56 } // namespace SymTab57 58 45 // #define DEBUG 59 46 60 47 namespace ResolvExpr { 61 62 // Template Helpers:63 template< typename Iterator1, typename Iterator2 >64 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {65 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {66 Type *commonType = 0;67 if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {68 return false;69 } // if70 commonTypes.push_back( commonType );71 } // for72 return ( list1Begin == list1End && list2Begin == list2End );73 }74 75 template< typename Iterator1, typename Iterator2 >76 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {77 std::list< Type* > commonTypes;78 if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions, openVars, indexer, commonTypes ) ) {79 deleteAll( commonTypes );80 return true;81 } else {82 return false;83 } // if84 }85 86 struct Unify_old : public WithShortCircuiting {87 Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );88 89 bool get_result() const { return result; }90 91 void previsit( BaseSyntaxNode * ) { visit_children = false; }92 93 void postvisit( VoidType * voidType );94 void postvisit( BasicType * basicType );95 void postvisit( PointerType * pointerType );96 void postvisit( ArrayType * arrayType );97 void postvisit( ReferenceType * refType );98 void postvisit( FunctionType * functionType );99 void postvisit( StructInstType * aggregateUseType );100 void postvisit( UnionInstType * aggregateUseType );101 void postvisit( EnumInstType * aggregateUseType );102 void postvisit( TraitInstType * aggregateUseType );103 void postvisit( TypeInstType * aggregateUseType );104 void postvisit( TupleType * tupleType );105 void postvisit( VarArgsType * varArgsType );106 void postvisit( ZeroType * zeroType );107 void postvisit( OneType * oneType );108 109 private:110 template< typename RefType > void handleRefType( RefType *inst, Type *other );111 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );112 113 bool result;114 Type *type2; // inherited115 TypeEnvironment &env;116 AssertionSet &needAssertions;117 AssertionSet &haveAssertions;118 const OpenVarSet &openVars;119 WidenMode widen;120 const SymTab::Indexer &indexer;121 };122 123 /// Attempts an inexact unification of type1 and type2.124 /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)125 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );126 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );127 128 bool unifyExact(129 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,130 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,131 WidenMode widen );132 133 bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {134 TypeEnvironment newEnv;135 OpenVarSet openVars, closedVars; // added closedVars136 AssertionSet needAssertions, haveAssertions;137 Type * newFirst = first->clone(), * newSecond = second->clone();138 env.apply( newFirst );139 env.apply( newSecond );140 141 // do we need to do this? Seems like we do, types should be able to be compatible if they142 // have free variables that can unify143 findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false );144 findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true );145 146 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );147 delete newFirst;148 delete newSecond;149 return result;150 }151 48 152 49 bool typesCompatible( … … 165 62 166 63 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() ); 167 }168 169 bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {170 TypeEnvironment newEnv;171 OpenVarSet openVars;172 AssertionSet needAssertions, haveAssertions;173 Type *newFirst = first->clone(), *newSecond = second->clone();174 env.apply( newFirst );175 env.apply( newSecond );176 newFirst->get_qualifiers() = Type::Qualifiers();177 newSecond->get_qualifiers() = Type::Qualifiers();178 179 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );180 delete newFirst;181 delete newSecond;182 return result;183 64 } 184 65 … … 218 99 subSecond, 219 100 newEnv, need, have, open, noWiden() ); 220 }221 222 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {223 OpenVarSet closedVars;224 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );225 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );226 Type *commonType = 0;227 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {228 if ( commonType ) {229 delete commonType;230 } // if231 return true;232 } else {233 return false;234 } // if235 }236 237 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) {238 OpenVarSet closedVars;239 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );240 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );241 return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType );242 }243 244 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {245 #ifdef DEBUG246 TypeEnvironment debugEnv( env );247 #endif248 if ( type1->get_qualifiers() != type2->get_qualifiers() ) {249 return false;250 }251 252 bool result;253 TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 );254 TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 );255 OpenVarSet::const_iterator entry1, entry2;256 if ( var1 ) {257 entry1 = openVars.find( var1->get_name() );258 } // if259 if ( var2 ) {260 entry2 = openVars.find( var2->get_name() );261 } // if262 bool isopen1 = var1 && ( entry1 != openVars.end() );263 bool isopen2 = var2 && ( entry2 != openVars.end() );264 265 if ( isopen1 && isopen2 ) {266 if ( entry1->second.kind != entry2->second.kind ) {267 result = false;268 } else {269 result = env.bindVarToVar(270 var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,271 haveAssertions, openVars, widen, indexer );272 }273 } else if ( isopen1 ) {274 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );275 } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?276 result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );277 } else {278 PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );279 type1->accept( comparator );280 result = comparator.pass.get_result();281 } // if282 #ifdef DEBUG283 std::cerr << "============ unifyExact" << std::endl;284 std::cerr << "type1 is ";285 type1->print( std::cerr );286 std::cerr << std::endl << "type2 is ";287 type2->print( std::cerr );288 std::cerr << std::endl << "openVars are ";289 printOpenVarSet( openVars, std::cerr, 8 );290 std::cerr << std::endl << "input env is " << std::endl;291 debugEnv.print( std::cerr, 8 );292 std::cerr << std::endl << "result env is " << std::endl;293 env.print( std::cerr, 8 );294 std::cerr << "result is " << result << std::endl;295 #endif296 return result;297 }298 299 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {300 return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );301 }302 303 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {304 Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();305 type1->get_qualifiers() = Type::Qualifiers();306 type2->get_qualifiers() = Type::Qualifiers();307 bool result;308 #ifdef DEBUG309 std::cerr << "unifyInexact type 1 is ";310 type1->print( std::cerr );311 std::cerr << " type 2 is ";312 type2->print( std::cerr );313 std::cerr << std::endl;314 #endif315 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {316 #ifdef DEBUG317 std::cerr << "unifyInexact: no exact unification found" << std::endl;318 #endif319 if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {320 common->tq = tq1.unify( tq2 );321 #ifdef DEBUG322 std::cerr << "unifyInexact: common type is ";323 common->print( std::cerr );324 std::cerr << std::endl;325 #endif326 result = true;327 } else {328 #ifdef DEBUG329 std::cerr << "unifyInexact: no common type found" << std::endl;330 #endif331 result = false;332 } // if333 } else {334 if ( tq1 != tq2 ) {335 if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {336 common = type1->clone();337 common->tq = tq1.unify( tq2 );338 result = true;339 } else {340 result = false;341 } // if342 } else {343 common = type1->clone();344 common->tq = tq1.unify( tq2 );345 result = true;346 } // if347 } // if348 type1->get_qualifiers() = tq1;349 type2->get_qualifiers() = tq2;350 return result;351 }352 353 Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )354 : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {355 }356 357 void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {358 result = dynamic_cast< VoidType* >( type2 );359 }360 361 void Unify_old::postvisit(BasicType *basicType) {362 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {363 result = basicType->get_kind() == otherBasic->get_kind();364 } // if365 }366 367 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {368 AssertionSet::iterator i = assertions.find( assert );369 if ( i != assertions.end() ) {370 i->second.isUsed = true;371 } // if372 }373 374 void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) {375 for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {376 for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {377 markAssertionSet( assertion1, *assert );378 markAssertionSet( assertion2, *assert );379 } // for380 } // for381 }382 383 void Unify_old::postvisit(PointerType *pointerType) {384 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {385 result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );386 markAssertions( haveAssertions, needAssertions, pointerType );387 markAssertions( haveAssertions, needAssertions, otherPointer );388 } // if389 }390 391 void Unify_old::postvisit(ReferenceType *refType) {392 if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {393 result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );394 markAssertions( haveAssertions, needAssertions, refType );395 markAssertions( haveAssertions, needAssertions, otherRef );396 } // if397 }398 399 void Unify_old::postvisit(ArrayType *arrayType) {400 ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );401 // to unify, array types must both be VLA or both not VLA402 // and must both have a dimension expression or not have a dimension403 if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {404 405 if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&406 arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {407 ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() );408 ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() );409 // see C11 Reference Manual 6.7.6.2.6410 // two array types with size specifiers that are integer constant expressions are411 // compatible if both size specifiers have the same constant value412 if ( ce1 && ce2 ) {413 Constant * c1 = ce1->get_constant();414 Constant * c2 = ce2->get_constant();415 416 if ( c1->get_value() != c2->get_value() ) {417 // does not unify if the dimension is different418 return;419 }420 }421 }422 423 result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );424 } // if425 }426 427 template< typename Iterator, typename Func >428 std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {429 std::list< Type * > types;430 for ( ; begin != end; ++begin ) {431 // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple432 flatten( toType( *begin ), back_inserter( types ) );433 }434 return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );435 }436 437 template< typename Iterator1, typename Iterator2 >438 bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {439 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };440 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {441 Type * t1 = (*list1Begin)->get_type();442 Type * t2 = (*list2Begin)->get_type();443 bool isTtype1 = Tuples::isTtype( t1 );444 bool isTtype2 = Tuples::isTtype( t2 );445 // xxx - assumes ttype must be last parameter446 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.447 if ( isTtype1 && ! isTtype2 ) {448 // combine all of the things in list2, then unify449 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );450 } else if ( isTtype2 && ! isTtype1 ) {451 // combine all of the things in list1, then unify452 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );453 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {454 return false;455 } // if456 } // for457 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype458 if ( list1Begin != list1End ) {459 // try unifying empty tuple type with ttype460 Type * t1 = (*list1Begin)->get_type();461 if ( Tuples::isTtype( t1 ) ) {462 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );463 } else return false;464 } else if ( list2Begin != list2End ) {465 // try unifying empty tuple type with ttype466 Type * t2 = (*list2Begin)->get_type();467 if ( Tuples::isTtype( t2 ) ) {468 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );469 } else return false;470 } else {471 return true;472 } // if473 }474 475 /// Finds ttypes and replaces them with their expansion, if known.476 /// This needs to be done so that satisfying ttype assertions is easier.477 /// If this isn't done then argument lists can have wildly different478 /// size and structure, when they should be compatible.479 struct TtypeExpander_old : public WithShortCircuiting {480 TypeEnvironment & tenv;481 TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}482 void premutate( TypeInstType * ) { visit_children = false; }483 Type * postmutate( TypeInstType * typeInst ) {484 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {485 // expand ttype parameter into its actual type486 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {487 delete typeInst;488 return eqvClass->type->clone();489 }490 }491 return typeInst;492 }493 };494 495 /// flattens a list of declarations, so that each tuple type has a single declaration.496 /// makes use of TtypeExpander to ensure ttypes are flat as well.497 void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {498 dst.clear();499 for ( DeclarationWithType * dcl : src ) {500 PassVisitor<TtypeExpander_old> expander( env );501 dcl->acceptMutator( expander );502 std::list< Type * > types;503 flatten( dcl->get_type(), back_inserter( types ) );504 for ( Type * t : types ) {505 // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.506 // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.507 t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);508 509 dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );510 }511 delete dcl;512 }513 }514 515 void Unify_old::postvisit(FunctionType *functionType) {516 FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );517 if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {518 // flatten the parameter lists for both functions so that tuple structure519 // doesn't affect unification. Must be a clone so that the types don't change.520 std::unique_ptr<FunctionType> flatFunc( functionType->clone() );521 std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );522 flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );523 flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );524 525 // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors526 if (527 (flatFunc->parameters.size() == flatOther->parameters.size() &&528 flatFunc->returnVals.size() == flatOther->returnVals.size())529 || flatFunc->isTtype()530 || flatOther->isTtype()531 ) {532 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {533 if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {534 535 // the original types must be used in mark assertions, since pointer comparisons are used536 markAssertions( haveAssertions, needAssertions, functionType );537 markAssertions( haveAssertions, needAssertions, otherFunction );538 539 result = true;540 } // if541 } // if542 } // if543 } // if544 }545 546 template< typename RefType >547 void Unify_old::handleRefType( RefType *inst, Type *other ) {548 // check that other type is compatible and named the same549 RefType *otherStruct = dynamic_cast< RefType* >( other );550 result = otherStruct && inst->name == otherStruct->name;551 }552 553 template< typename RefType >554 void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {555 // Check that other type is compatible and named the same556 handleRefType( inst, other );557 if ( ! result ) return;558 // Check that parameters of types unify, if any559 std::list< Expression* > params = inst->parameters;560 std::list< Expression* > otherParams = ((RefType*)other)->parameters;561 562 std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();563 for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {564 TypeExpr *param = dynamic_cast< TypeExpr* >(*it);565 assertf(param, "Aggregate parameters should be type expressions");566 TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);567 assertf(otherParam, "Aggregate parameters should be type expressions");568 569 Type* paramTy = param->get_type();570 Type* otherParamTy = otherParam->get_type();571 572 bool tupleParam = Tuples::isTtype( paramTy );573 bool otherTupleParam = Tuples::isTtype( otherParamTy );574 575 if ( tupleParam && otherTupleParam ) {576 ++it; ++jt; // skip ttype parameters for break577 } else if ( tupleParam ) {578 // bundle other parameters into tuple to match579 std::list< Type * > binderTypes;580 581 do {582 binderTypes.push_back( otherParam->get_type()->clone() );583 ++jt;584 585 if ( jt == otherParams.end() ) break;586 587 otherParam = dynamic_cast< TypeExpr* >(*jt);588 assertf(otherParam, "Aggregate parameters should be type expressions");589 } while (true);590 591 otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };592 ++it; // skip ttype parameter for break593 } else if ( otherTupleParam ) {594 // bundle parameters into tuple to match other595 std::list< Type * > binderTypes;596 597 do {598 binderTypes.push_back( param->get_type()->clone() );599 ++it;600 601 if ( it == params.end() ) break;602 603 param = dynamic_cast< TypeExpr* >(*it);604 assertf(param, "Aggregate parameters should be type expressions");605 } while (true);606 607 paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };608 ++jt; // skip ttype parameter for break609 }610 611 if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {612 result = false;613 return;614 }615 616 // ttype parameter should be last617 if ( tupleParam || otherTupleParam ) break;618 }619 result = ( it == params.end() && jt == otherParams.end() );620 }621 622 void Unify_old::postvisit(StructInstType *structInst) {623 handleGenericRefType( structInst, type2 );624 }625 626 void Unify_old::postvisit(UnionInstType *unionInst) {627 handleGenericRefType( unionInst, type2 );628 }629 630 void Unify_old::postvisit(EnumInstType *enumInst) {631 handleRefType( enumInst, type2 );632 }633 634 void Unify_old::postvisit(TraitInstType *contextInst) {635 handleRefType( contextInst, type2 );636 }637 638 void Unify_old::postvisit(TypeInstType *typeInst) {639 assert( openVars.find( typeInst->get_name() ) == openVars.end() );640 TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );641 if ( otherInst && typeInst->get_name() == otherInst->get_name() ) {642 result = true;643 /// } else {644 /// NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() );645 /// if ( nt ) {646 /// TypeDecl *type = dynamic_cast< TypeDecl* >( nt );647 /// assert( type );648 /// if ( type->get_base() ) {649 /// result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );650 /// }651 /// }652 } // if653 }654 655 template< typename Iterator1, typename Iterator2 >656 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {657 auto get_type = [](Type * t) { return t; };658 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {659 Type * t1 = *list1Begin;660 Type * t2 = *list2Begin;661 bool isTtype1 = Tuples::isTtype( t1 );662 bool isTtype2 = Tuples::isTtype( t2 );663 // xxx - assumes ttype must be last parameter664 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.665 if ( isTtype1 && ! isTtype2 ) {666 // combine all of the things in list2, then unify667 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );668 } else if ( isTtype2 && ! isTtype1 ) {669 // combine all of the things in list1, then unify670 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );671 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {672 return false;673 } // if674 675 } // for676 if ( list1Begin != list1End ) {677 // try unifying empty tuple type with ttype678 Type * t1 = *list1Begin;679 if ( Tuples::isTtype( t1 ) ) {680 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );681 } else return false;682 } else if ( list2Begin != list2End ) {683 // try unifying empty tuple type with ttype684 Type * t2 = *list2Begin;685 if ( Tuples::isTtype( t2 ) ) {686 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );687 } else return false;688 } else {689 return true;690 } // if691 }692 693 void Unify_old::postvisit(TupleType *tupleType) {694 if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {695 std::unique_ptr<TupleType> flat1( tupleType->clone() );696 std::unique_ptr<TupleType> flat2( otherTuple->clone() );697 std::list<Type *> types1, types2;698 699 PassVisitor<TtypeExpander_old> expander( env );700 flat1->acceptMutator( expander );701 flat2->acceptMutator( expander );702 703 flatten( flat1.get(), back_inserter( types1 ) );704 flatten( flat2.get(), back_inserter( types2 ) );705 706 result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );707 } // if708 }709 710 void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {711 result = dynamic_cast< VarArgsType* >( type2 );712 }713 714 void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {715 result = dynamic_cast< ZeroType* >( type2 );716 }717 718 void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {719 result = dynamic_cast< OneType* >( type2 );720 }721 722 Type * extractResultType( FunctionType * function ) {723 if ( function->get_returnVals().size() == 0 ) {724 return new VoidType( Type::Qualifiers() );725 } else if ( function->get_returnVals().size() == 1 ) {726 return function->get_returnVals().front()->get_type()->clone();727 } else {728 std::list< Type * > types;729 for ( DeclarationWithType * decl : function->get_returnVals() ) {730 types.push_back( decl->get_type()->clone() );731 } // for732 return new TupleType( Type::Qualifiers(), types );733 }734 101 } 735 102 -
src/ResolvExpr/Unify.h
r790d835 rc6b4432 20 20 #include "AST/Node.hpp" // for ptr 21 21 #include "AST/TypeEnvironment.hpp" // for TypeEnvironment, AssertionSet, OpenVarSet 22 #include "Common/utility.h" // for deleteAll23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data24 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet25 22 #include "WidenMode.h" // for WidenMode 26 27 class Type;28 class TypeInstType;29 namespace SymTab {30 class Indexer;31 }32 23 33 24 namespace ast { … … 37 28 38 29 namespace ResolvExpr { 39 40 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );41 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );42 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );43 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );44 45 bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );46 bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );47 48 inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {49 TypeEnvironment env;50 return typesCompatible( t1, t2, indexer, env );51 }52 53 inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {54 TypeEnvironment env;55 return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );56 }57 30 58 31 bool unify( … … 85 58 const ast::TypeEnvironment & env = {} ); 86 59 87 /// Creates the type represented by the list of returnVals in a FunctionType.88 /// The caller owns the return value.89 Type * extractResultType( FunctionType * functionType );90 60 /// Creates or extracts the type represented by returns in a `FunctionType`. 91 61 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ); -
src/ResolvExpr/module.mk
r790d835 rc6b4432 18 18 ResolvExpr/AdjustExprType.cc \ 19 19 ResolvExpr/AdjustExprType.hpp \ 20 ResolvExpr/Alternative.cc \21 ResolvExpr/AlternativeFinder.cc \22 ResolvExpr/AlternativeFinder.h \23 ResolvExpr/Alternative.h \24 20 ResolvExpr/Candidate.cpp \ 25 21 ResolvExpr/CandidateFinder.cpp \ … … 35 31 ResolvExpr/CurrentObject.cc \ 36 32 ResolvExpr/CurrentObject.h \ 37 ResolvExpr/ExplodedActual.cc \38 ResolvExpr/ExplodedActual.h \39 33 ResolvExpr/ExplodedArg.cpp \ 40 34 ResolvExpr/ExplodedArg.hpp \ 41 35 ResolvExpr/FindOpenVars.cc \ 42 36 ResolvExpr/FindOpenVars.h \ 43 ResolvExpr/Occurs.cc \44 37 ResolvExpr/PolyCost.cc \ 45 38 ResolvExpr/PolyCost.hpp \ … … 50 43 ResolvExpr/RenameVars.cc \ 51 44 ResolvExpr/RenameVars.h \ 52 ResolvExpr/ResolveAssertions.cc \53 ResolvExpr/ResolveAssertions.h \54 45 ResolvExpr/Resolver.cc \ 55 46 ResolvExpr/Resolver.h \ … … 61 52 ResolvExpr/SpecCost.cc \ 62 53 ResolvExpr/SpecCost.hpp \ 63 ResolvExpr/TypeEnvironment.cc \64 ResolvExpr/TypeEnvironment.h \65 54 ResolvExpr/typeops.h \ 66 55 ResolvExpr/Unify.cc \ … … 69 58 70 59 SRC += $(SRC_RESOLVEXPR) \ 71 ResolvExpr/AlternativePrinter.cc \72 ResolvExpr/AlternativePrinter.h \73 60 ResolvExpr/CandidatePrinter.cpp \ 74 61 ResolvExpr/CandidatePrinter.hpp \ -
src/ResolvExpr/typeops.h
r790d835 rc6b4432 19 19 20 20 #include "AST/Type.hpp" 21 #include "SynTree/Type.h"22 21 23 22 namespace SymTab { … … 52 51 std::copy( i.begin(), i.end(), inserter ); 53 52 *out++ = result; 54 }55 }56 57 // in Occurs.cc58 bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env );59 // new AST version in TypeEnvironment.cpp (only place it was used in old AST)60 61 template<typename Iter>62 bool occursIn( Type* ty, Iter begin, Iter end, const TypeEnvironment & env ) {63 while ( begin != end ) {64 if ( occurs( ty, *begin, env ) ) return true;65 ++begin;66 }67 return false;68 }69 70 /// flatten tuple type into list of types71 template< typename OutputIterator >72 void flatten( Type * type, OutputIterator out ) {73 if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) {74 for ( Type * t : tupleType->get_types() ) {75 flatten( t, out );76 }77 } else {78 *out++ = type->clone();79 53 } 80 54 } … … 120 94 return tupleFromTypes( tys.begin(), tys.end() ); 121 95 } 122 123 // in TypeEnvironment.cc124 bool isFtype( const Type * type );125 96 } // namespace ResolvExpr 126 97
Note:
See TracChangeset
for help on using the changeset viewer.