Changeset 46da46b


Ignore:
Timestamp:
May 2, 2023, 3:44:31 AM (12 months ago)
Author:
Fangren Yu <f37yu@…>
Branches:
ast-experimental, master
Children:
0c840fc
Parents:
1ab773e0
Message:

current progress

Location:
src
Files:
23 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Convert.cpp

    r1ab773e0 r46da46b  
    23312331                                old->location,
    23322332                                GET_ACCEPT_1(arg, Expr),
    2333                                 old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast
     2333                                old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast,
     2334                                (ast::CastExpr::CastKind) old->kind
    23342335                        )
    23352336                );
  • src/AST/Expr.cpp

    r1ab773e0 r46da46b  
    186186// --- CastExpr
    187187
    188 CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g )
    189 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
     188CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g, CastKind kind )
     189: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ), kind( kind ) {}
    190190
    191191bool CastExpr::get_lvalue() const {
  • src/AST/Expr.hpp

    r1ab773e0 r46da46b  
    5555                const Expr * e )
    5656        : decl( id ), declptr( declptr ), actualType( actual ), formalType( formal ), expr( e ) {}
     57
     58        operator bool() {return declptr;}
    5759};
    5860
     
    334336        GeneratedFlag isGenerated;
    335337
     338        enum CastKind {
     339                Default, // C
     340                Coerce, // reinterpret cast
     341                Return  // overload selection
     342        };
     343
     344        CastKind kind = Default;
     345
    336346        CastExpr( const CodeLocation & loc, const Expr * a, const Type * to,
    337                 GeneratedFlag g = GeneratedCast ) : Expr( loc, to ), arg( a ), isGenerated( g ) {}
     347                GeneratedFlag g = GeneratedCast, CastKind kind = Default ) : Expr( loc, to ), arg( a ), isGenerated( g ), kind( kind ) {}
    338348        /// Cast-to-void
    339         CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast );
     349        CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast, CastKind kind = Default );
    340350
    341351        /// Wrap a cast expression around an existing expression (always generated)
  • src/AST/Type.hpp

    r1ab773e0 r46da46b  
    454454        bool operator==(const TypeEnvKey & other) const;
    455455        bool operator<(const TypeEnvKey & other) const;
    456 };
     456        operator bool() {return base;}
     457};
     458
    457459
    458460/// tuple type e.g. `[int, char]`
  • src/AST/TypeEnvironment.cpp

    r1ab773e0 r46da46b  
    135135                }
    136136        }
    137         sub.normalize();
     137        // sub.normalize();
    138138}
    139139
  • src/GenPoly/SpecializeNew.cpp

    r1ab773e0 r46da46b  
    112112        using namespace ResolvExpr;
    113113        ast::OpenVarSet openVars, closedVars;
    114         ast::AssertionSet need, have;
    115         findOpenVars( formalType, openVars, closedVars, need, have, FirstClosed );
    116         findOpenVars( actualType, openVars, closedVars, need, have, FirstOpen );
     114        ast::AssertionSet need, have; // unused
     115        ast::TypeEnvironment env; // unused
     116        // findOpenVars( formalType, openVars, closedVars, need, have, FirstClosed );
     117        findOpenVars( actualType, openVars, closedVars, need, have, env, FirstOpen );
    117118        for ( const ast::OpenVarSet::value_type & openVar : openVars ) {
    118119                const ast::Type * boundType = subs->lookup( openVar.first );
     
    124125                        if ( closedVars.find( *inst ) == closedVars.end() ) {
    125126                                return true;
     127                        }
     128                        else {
     129                                assertf(false, "closed: %s", inst->name.c_str());
    126130                        }
    127131                // Otherwise, the variable is bound to a concrete type.
  • src/Parser/ExpressionNode.cc

    r1ab773e0 r46da46b  
    544544}; // OperName
    545545
    546 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node ) {
     546Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node, CastExpr::CastKind kind ) {
    547547        Type * targetType = maybeMoveBuildType( decl_node );
    548548        if ( dynamic_cast< VoidType * >( targetType ) ) {
    549549                delete targetType;
    550                 return new CastExpr( maybeMoveBuild< Expression >(expr_node), false );
     550                return new CastExpr( maybeMoveBuild< Expression >(expr_node), false, kind );
    551551        } else {
    552                 return new CastExpr( maybeMoveBuild< Expression >(expr_node), targetType, false );
     552                return new CastExpr( maybeMoveBuild< Expression >(expr_node), targetType, false, kind );
    553553        } // if
    554554} // build_cast
  • src/Parser/ParseNode.h

    r1ab773e0 r46da46b  
    189189DimensionExpr * build_dimensionref( const std::string * name );
    190190
    191 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
     191Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node, CastExpr::CastKind kind = CastExpr::Default );
    192192Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node );
    193193Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
  • src/Parser/parser.yy

    r1ab773e0 r46da46b  
    905905                { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild<Expression>( $5 ), maybeMoveBuildType( $3 ) ) ); }
    906906        | '(' RETURN type_no_function ')' cast_expression       // CFA
    907                 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }
     907                { $$ = new ExpressionNode( build_cast( $3, $5, CastExpr::Return ) ); }
    908908        | '(' COERCE type_no_function ')' cast_expression       // CFA
    909909                { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; }
  • src/ResolvExpr/Candidate.hpp

    r1ab773e0 r46da46b  
    9191
    9292/// Holdover behaviour from old `findMinCost` -- xxx -- can maybe be eliminated?
     93/*
    9394static inline void promoteCvtCost( CandidateList & candidates ) {
    9495        for ( CandidateRef & r : candidates ) {
     
    9697        }
    9798}
     99*/
    98100
    99101void print( std::ostream & os, const Candidate & cand, Indenter indent = {} );
  • src/ResolvExpr/CandidateFinder.cpp

    r1ab773e0 r46da46b  
    3030#include "Resolver.h"
    3131#include "ResolveTypeof.h"
     32#include "WidenMode.h"
    3233#include "SatisfyAssertions.hpp"
    3334#include "typeops.h"              // for adjustExprType, conversionCost, polyCost, specCost
     
    700701                                // attempt to narrow based on expected target type
    701702                                const ast::Type * returnType = funcType->returns.front();
    702                                 if ( ! unify(
    703                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
    704                                 ) {
    705                                         // unification failed, do not pursue this candidate
    706                                         return;
     703                                if ( selfFinder.strictMode ) {
     704                                        if ( ! unifyExact(
     705                                                returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden(), symtab ) // xxx - is no widening correct?
     706                                        ) {
     707                                                // unification failed, do not pursue this candidate
     708                                                return;
     709                                        }
     710                                }
     711                                else {
     712                                        if ( ! unify(
     713                                                returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     714                                        ) {
     715                                                // unification failed, do not pursue this candidate
     716                                                return;
     717                                        }
    707718                                }
    708719                        }
     
    825836
    826837                        if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
    827                                 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
     838                                addAggMembers( structInst, aggrExpr, *cand, Cost::unsafe, "" );
    828839                        } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    829                                 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
     840                                addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
    830841                        }
    831842                }
     
    958969                                        if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
    959970                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     971                                                        // if (!selfFinder.allowVoid && function->returns.empty()) continue;
    960972                                                        CandidateRef newFunc{ new Candidate{ *func } };
    961973                                                        newFunc->expr =
     
    10081020                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
    10091021
     1022                        // only keep the best matching intrinsic result to match C semantics (no unexpected narrowing/widening)
     1023                        // TODO: keep one for each set of argument candidates?
     1024                        Cost intrinsicCost = Cost::infinity;
     1025                        CandidateList intrinsicResult;
     1026
    10101027                        // Compute conversion costs
    10111028                        for ( CandidateRef & withFunc : found ) {
     
    10301047                                if ( cvtCost != Cost::infinity ) {
    10311048                                        withFunc->cvtCost = cvtCost;
    1032                                         candidates.emplace_back( std::move( withFunc ) );
    1033                                 }
    1034                         }
     1049                                        withFunc->cost += cvtCost;     
     1050                                        auto func = withFunc->expr.strict_as<ast::ApplicationExpr>()->func.as<ast::VariableExpr>();
     1051                                        if (func && func->var->linkage == ast::Linkage::Intrinsic) {
     1052                                                if (withFunc->cost < intrinsicCost) {
     1053                                                        intrinsicResult.clear();
     1054                                                        intrinsicCost = withFunc->cost;
     1055                                                }
     1056                                                if (withFunc->cost == intrinsicCost) {
     1057                                                        intrinsicResult.emplace_back(std::move(withFunc));
     1058                                                }
     1059                                        }       
     1060                                        else {
     1061                                                candidates.emplace_back( std::move( withFunc ) );
     1062                                        }
     1063                                }
     1064                        }
     1065                        spliceBegin( candidates, intrinsicResult );
    10351066                        found = std::move( candidates );
    10361067
    10371068                        // use a new list so that candidates are not examined by addAnonConversions twice
    1038                         CandidateList winners = findMinCost( found );
    1039                         promoteCvtCost( winners );
     1069                        // CandidateList winners = findMinCost( found );
     1070                        // promoteCvtCost( winners );
    10401071
    10411072                        // function may return a struct/union value, in which case we need to add candidates
    10421073                        // for implicit conversions to each of the anonymous members, which must happen after
    10431074                        // `findMinCost`, since anon conversions are never the cheapest
    1044                         for ( const CandidateRef & c : winners ) {
     1075                        for ( const CandidateRef & c : found ) {
    10451076                                addAnonConversions( c );
    10461077                        }
    1047                         spliceBegin( candidates, winners );
    1048 
    1049                         if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
     1078                        // would this be too slow when we don't check cost anymore?
     1079                        spliceBegin( candidates, found );
     1080
     1081                        if ( candidates.empty() && targetType && ! targetType->isVoid() && !selfFinder.strictMode ) {
    10501082                                // If resolution is unsuccessful with a target type, try again without, since it
    10511083                                // will sometimes succeed when it wouldn't with a target type binding.
     
    10931125
    10941126                        CandidateFinder finder( context, tenv, toType );
     1127                        if (toType->isVoid()) {
     1128                                finder.allowVoid = true;
     1129                        }
     1130                        if ( castExpr->kind == ast::CastExpr::Return ) {
     1131                                finder.strictMode = true;
     1132                                finder.find( castExpr->arg, ResolvMode::withAdjustment() );
     1133
     1134                                // return casts are eliminated (merely selecting an overload, no actual operation)
     1135                                candidates = std::move(finder.candidates);
     1136                        }
    10951137                        finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    10961138
     
    10981140
    10991141                        CandidateList matches;
     1142                        Cost minExprCost = Cost::infinity;
     1143                        Cost minCastCost = Cost::infinity;
    11001144                        for ( CandidateRef & cand : finder.candidates ) {
    11011145                                ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     
    11291173                                        // count one safe conversion for each value that is thrown away
    11301174                                        thisCost.incSafe( discardedValues );
    1131                                         CandidateRef newCand = std::make_shared<Candidate>(
    1132                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1133                                                 copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
    1134                                                 cand->cost + thisCost );
    1135                                         inferParameters( newCand, matches );
    1136                                 }
    1137                         }
    1138 
    1139                         // select first on argument cost, then conversion cost
    1140                         CandidateList minArgCost = findMinCost( matches );
    1141                         promoteCvtCost( minArgCost );
    1142                         candidates = findMinCost( minArgCost );
     1175                                        // select first on argument cost, then conversion cost
     1176                                        if (cand->cost < minExprCost || cand->cost == minExprCost && thisCost < minCastCost) {
     1177                                                minExprCost = cand->cost;
     1178                                                minCastCost = thisCost;
     1179                                                matches.clear();
     1180
     1181
     1182                                        }
     1183                                        // ambiguous case, still output candidates to print in error message
     1184                                        if (cand->cost == minExprCost && thisCost == minCastCost) {
     1185                                                CandidateRef newCand = std::make_shared<Candidate>(
     1186                                                        restructureCast( cand->expr, toType, castExpr->isGenerated ),
     1187                                                        copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost);
     1188                                                // currently assertions are always resolved immediately so this should have no effect.
     1189                                                // if this somehow changes in the future (e.g. delayed by indeterminate return type)
     1190                                                // we may need to revisit the logic.
     1191                                                inferParameters( newCand, matches );
     1192                                        }
     1193                                        // else skip, better alternatives found
     1194
     1195                                }
     1196                        }
     1197                        candidates = std::move(matches);
     1198
     1199                        //CandidateList minArgCost = findMinCost( matches );
     1200                        //promoteCvtCost( minArgCost );
     1201                        //candidates = findMinCost( minArgCost );
    11431202                }
    11441203
     
    12611320
    12621321                                CandidateRef newCand = std::make_shared<Candidate>(
    1263                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
    1264                                         cost );
     1322                                        newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, cost );
    12651323
    12661324                                if (newCand->expr->env) {
     
    14071465                        // candidates for true result
    14081466                        CandidateFinder finder2( context, tenv );
     1467                        finder2.allowVoid = true;
    14091468                        finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
    14101469                        if ( finder2.candidates.empty() ) return;
     
    14121471                        // candidates for false result
    14131472                        CandidateFinder finder3( context, tenv );
     1473                        finder3.allowVoid = true;
    14141474                        finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    14151475                        if ( finder3.candidates.empty() ) return;
     
    14781538                void postvisit( const ast::ConstructorExpr * ctorExpr ) {
    14791539                        CandidateFinder finder( context, tenv );
     1540                        finder.allowVoid = true;
    14801541                        finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
    14811542                        for ( CandidateRef & r : finder.candidates ) {
     
    15941655                                CandidateFinder finder( context, tenv, toType );
    15951656                                finder.find( initExpr->expr, ResolvMode::withAdjustment() );
     1657
     1658                                Cost minExprCost = Cost::infinity;
     1659                                Cost minCastCost = Cost::infinity;
    15961660                                for ( CandidateRef & cand : finder.candidates ) {
    15971661                                        if(reason.code == NotFound) reason.code = NoMatch;
     
    16311695                                                // count one safe conversion for each value that is thrown away
    16321696                                                thisCost.incSafe( discardedValues );
    1633                                                 CandidateRef newCand = std::make_shared<Candidate>(
     1697                                                if (cand->cost < minExprCost || cand->cost == minExprCost && thisCost < minCastCost) {
     1698                                                        minExprCost = cand->cost;
     1699                                                        minCastCost = thisCost;
     1700                                                        matches.clear();
     1701                                                }
     1702                                                // ambiguous case, still output candidates to print in error message
     1703                                                if (cand->cost == minExprCost && thisCost == minCastCost) {
     1704                                                        CandidateRef newCand = std::make_shared<Candidate>(
    16341705                                                        new ast::InitExpr{
    16351706                                                                initExpr->location, restructureCast( cand->expr, toType ),
    16361707                                                                initAlt.designation },
    1637                                                         std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
    1638                                                 inferParameters( newCand, matches );
    1639                                         }
     1708                                                        std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );
     1709                                                        // currently assertions are always resolved immediately so this should have no effect.
     1710                                                        // if this somehow changes in the future (e.g. delayed by indeterminate return type)
     1711                                                        // we may need to revisit the logic.
     1712                                                        inferParameters( newCand, matches );
     1713                                                }
     1714
     1715                                        }
     1716                                       
    16401717                                }
    16411718
     
    16431720
    16441721                        // select first on argument cost, then conversion cost
    1645                         CandidateList minArgCost = findMinCost( matches );
    1646                         promoteCvtCost( minArgCost );
    1647                         candidates = findMinCost( minArgCost );
     1722                        // CandidateList minArgCost = findMinCost( matches );
     1723                        // promoteCvtCost( minArgCost );
     1724                        // candidates = findMinCost( minArgCost );
     1725                        candidates = std::move(matches);
    16481726                }
    16491727
     
    17241802                        auto found = selected.find( mangleName );
    17251803                        if ( found != selected.end() ) {
    1726                                 if ( newCand->cost < found->second.candidate->cost ) {
     1804                                // tiebreaking by picking the lower cost on CURRENT expression
     1805                                // NOTE: this behavior is different from C semantics.
     1806                                // Specific remediations are performed for C operators at postvisit(UntypedExpr).
     1807                                // Further investigations may take place.
     1808                                if ( newCand->cost < found->second.candidate->cost
     1809                                        || (newCand->cost == found->second.candidate->cost && newCand->cvtCost < found->second.candidate->cvtCost) ) {
    17271810                                        PRINT(
    17281811                                                std::cerr << "cost " << newCand->cost << " beats "
     
    17311814
    17321815                                        found->second = PruneStruct{ newCand };
    1733                                 } else if ( newCand->cost == found->second.candidate->cost ) {
     1816                                } else if ( newCand->cost == found->second.candidate->cost && newCand->cvtCost == found->second.candidate->cvtCost) {
    17341817                                        // if one of the candidates contains a deleted identifier, can pick the other,
    17351818                                        // since deleted expressions should not be ambiguous if there is another option
     
    18221905        */
    18231906
    1824         if ( mode.prune ) {
     1907        // if ( mode.prune ) {
     1908        // optimization: don't prune for NameExpr since it never has cost
     1909        if ( mode.prune && !dynamic_cast<const ast::NameExpr *>(expr)) {
    18251910                // trim candidates to single best one
    18261911                PRINT(
  • src/ResolvExpr/CandidateFinder.hpp

    r1ab773e0 r46da46b  
    3333        const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
    3434        ast::ptr< ast::Type > targetType;  ///< Target type for resolution
     35        bool strictMode = false;           ///< If set to true, requires targetType to be exact match (inside return cast)
     36        bool allowVoid = false;            ///< If set to true, allow void-returning function calls (only top level, cast to void and first in comma)
    3537        std::set< std::string > otypeKeys;  /// different type may map to same key
    3638
  • src/ResolvExpr/CastCost.cc

    r1ab773e0 r46da46b  
    229229        if ( typesCompatibleIgnoreQualifiers( src, dst, symtab, env ) ) {
    230230                PRINT( std::cerr << "compatible!" << std::endl; )
     231                if (dynamic_cast<const ast::ZeroType *>(dst) || dynamic_cast<const ast::OneType *>(dst)) {
     232                        return Cost::spec;
     233                }
    231234                return Cost::zero;
    232235        } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
  • src/ResolvExpr/CommonType.cc

    r1ab773e0 r46da46b  
    695695                        if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
    696696                                #warning remove casts when `commonTypes` moved to new AST
     697                               
     698                                /*
    697699                                ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
    698700                                if (
     
    704706                                        result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
    705707                                }
     708                                */
     709                                ast::BasicType::Kind kind;
     710                                if (basic->kind != basic2->kind && !widen.first && !widen.second) return;
     711                                else if (!widen.first) kind = basic->kind; // widen.second
     712                                else if (!widen.second) kind = basic2->kind;
     713                                else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
     714                                // xxx - what does qualifiers even do here??
     715                                if ( (basic->qualifiers >= basic2->qualifiers || widen.first)
     716                                        && (basic->qualifiers <= basic2->qualifiers || widen.second) ) {
     717                                        result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
     718                                }
     719                               
    706720                        } else if (
    707721                                dynamic_cast< const ast::ZeroType * >( type2 )
     
    710724                                #warning remove casts when `commonTypes` moved to new AST
    711725                                ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
    712                                 if (
    713                                         ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
     726                                /*
     727                                if ( // xxx - what does qualifier even do here??
     728                                        ( ( basic->qualifiers >= type2->qualifiers )
    714729                                                || widen.first )
    715                                         && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
     730                                         && ( ( /* kind != basic->kind && basic->qualifiers <= type2->qualifiers )
    716731                                                || widen.second )
    717                                 ) {
    718                                         result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
     732                                )
     733                                */
     734                                if (widen.second) {
     735                                        result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers };
    719736                                }
    720737                        } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
     
    744761                                auto entry = open.find( *var );
    745762                                if ( entry != open.end() ) {
     763                                // if (tenv.lookup(*var)) {
    746764                                        ast::AssertionSet need, have;
    747765                                        if ( ! tenv.bindVar(
  • src/ResolvExpr/ConversionCost.cc

    r1ab773e0 r46da46b  
    702702
    703703        cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
     704
     705        // xxx - should qualifiers be considered in pass-by-value?
     706        /*
    704707        if ( refType->base->qualifiers == dst->qualifiers ) {
    705708                cost.incReference();
     
    709712                cost.incUnsafe();
    710713        }
     714        */
     715        cost.incReference();
    711716}
    712717
     
    792797                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    793798                }
     799                // this has the effect of letting any expr such as x+0, x+1 to be typed
     800                // the same as x, instead of at least int. are we willing to sacrifice this little
     801                // bit of coherence with C?
     802                // TODO: currently this does not work when no zero/one overloads exist. Find a fix for it.
     803                // cost = Cost::zero;
    794804        } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
    795805                cost = Cost::zero;
    796806                // +1 for zero_t ->, +1 for disambiguation
    797807                cost.incSafe( maxIntCost + 2 );
     808                // assuming 0p is supposed to be used for pointers?
    798809        }
    799810}
     
    804815                cost = Cost::zero;
    805816        } else if ( const ast::BasicType * dstAsBasic =
    806                         dynamic_cast< const ast::BasicType * >( dst ) ) {
     817                        dynamic_cast< const ast::BasicType * >( dst ) ) {               
    807818                int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ];
    808819                if ( -1 == tableResult ) {
     
    813824                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    814825                }
     826               
     827                // cost = Cost::zero;
    815828        }
    816829}
  • src/ResolvExpr/FindOpenVars.cc

    r1ab773e0 r46da46b  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
     23#include "AST/TypeEnvironment.hpp"
    2324#include "Common/PassVisitor.h"
    2425#include "SynTree/Declaration.h"  // for TypeDecl, DeclarationWithType (ptr ...
    2526#include "SynTree/Type.h"         // for Type, Type::ForallList, ArrayType
     27
     28#include <iostream>
    2629
    2730namespace ResolvExpr {
     
    102105                        ast::AssertionSet & need;
    103106                        ast::AssertionSet & have;
     107                        ast::TypeEnvironment & env;
    104108                        bool nextIsOpen;
    105109
    106110                        FindOpenVars_new(
    107111                                ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n,
    108                                 ast::AssertionSet & h, FirstMode firstIsOpen )
    109                         : open( o ), closed( c ), need( n ), have( h ), nextIsOpen( firstIsOpen ) {}
     112                                ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen )
     113                        : open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {}
    110114
    111115                        void previsit( const ast::FunctionType * type ) {
    112116                                // mark open/closed variables
    113117                                if ( nextIsOpen ) {
     118                                        // trying to remove this from resolver.
     119                                        // occasionally used in other parts so not deleting right now.
     120
     121                                        // insert open variables unbound to environment.
     122                                        env.add(type->forall);
     123
    114124                                        for ( auto & decl : type->forall ) {
    115125                                                open[ *decl ] = ast::TypeData{ decl->base };
     
    137147        void findOpenVars(
    138148                        const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
    139                         ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen ) {
    140                 ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, firstIsOpen };
     149                        ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) {
     150                ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, env, firstIsOpen };
    141151                type->accept( finder );
     152
     153                if (!closed.empty()) {
     154                        std::cerr << "closed: ";
     155                        for (auto& i : closed) {
     156                                std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';
     157                        }
     158                        std::cerr << std::endl;
     159                }
    142160        }
    143161} // namespace ResolvExpr
  • src/ResolvExpr/FindOpenVars.h

    r1ab773e0 r46da46b  
    3333        void findOpenVars(
    3434                const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
    35                 ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen );
     35                ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen );
    3636} // namespace ResolvExpr
    3737
  • src/ResolvExpr/Resolver.cc

    r1ab773e0 r46da46b  
    10091009                        ast::TypeEnvironment env;
    10101010                        CandidateFinder finder( context, env );
     1011                        finder.allowVoid = true;
    10111012                        finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
    10121013                        --recursion_level;
     
    10521053
    10531054                        // promote candidate.cvtCost to .cost
    1054                         promoteCvtCost( winners );
     1055                        // promoteCvtCost( winners );
    10551056
    10561057                        // produce ambiguous errors, if applicable
  • src/ResolvExpr/SatisfyAssertions.cpp

    r1ab773e0 r46da46b  
    1616#include "SatisfyAssertions.hpp"
    1717
     18#include <iostream>
    1819#include <algorithm>
    1920#include <cassert>
     
    4243#include "SymTab/Mangler.h"
    4344
     45
     46
    4447namespace ResolvExpr {
    4548
     
    6265                        ast::AssertionSet && h, ast::AssertionSet && n, ast::OpenVarSet && o, ast::UniqueId rs )
    6366                : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ),
    64                   need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {}
     67                  need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {
     68                        if (!have.empty()) {
     69                                std::cerr << c.id->location << ':' << c.id->name << std::endl;
     70                        }
     71                  }
    6572        };
    6673
     
    136143        };
    137144
    138         /// Adds a captured assertion to the symbol table
    139         void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) {
    140                 for ( auto & i : have ) {
    141                         if ( i.second.isUsed ) { symtab.addId( i.first->var ); }
    142                 }
    143         }
     145
    144146
    145147        /// Binds a single assertion, updating satisfaction state
     
    152154                        "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
    153155
    154                 ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cvtCost );
     156                ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cost );
    155157                varExpr->result = match.adjType;
    156158                if ( match.resnSlot ) { varExpr->inferred.resnSlots().emplace_back( match.resnSlot ); }
     
    162164
    163165        /// Satisfy a single assertion
    164         bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool allowConversion = false, bool skipUnbound = false) {
     166        bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool skipUnbound = false) {
    165167                // skip unused assertions
     168                static unsigned int cnt = 0;
    166169                if ( ! assn.second.isUsed ) return true;
    167170
     171                if (assn.first->var->name[1] == '|') std::cerr << ++cnt << std::endl;
     172
    168173                // find candidates that unify with the desired type
    169                 AssnCandidateList matches;
     174                AssnCandidateList matches, inexactMatches;
    170175
    171176                std::vector<ast::SymbolTable::IdData> candidates;
     
    209214
    210215                        ast::OpenVarSet closed;
    211                         findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed );
    212                         findOpenVars( adjType, newOpen, closed, newNeed, have, FirstOpen );
    213                         if ( allowConversion ) {
     216                        // findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed );
     217                        findOpenVars( adjType, newOpen, closed, newNeed, have, newEnv, FirstOpen );
     218                        ast::TypeEnvironment tempNewEnv {newEnv};
     219
     220                        if ( unifyExact( toType, adjType, tempNewEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) {
     221                                // set up binding slot for recursive assertions
     222                                ast::UniqueId crntResnSlot = 0;
     223                                if ( ! newNeed.empty() ) {
     224                                        crntResnSlot = ++globalResnSlot;
     225                                        for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; }
     226                                }
     227
     228                                matches.emplace_back(
     229                                        cdata, adjType, std::move( tempNewEnv ), std::move( have ), std::move( newNeed ),
     230                                        std::move( newOpen ), crntResnSlot );
     231                        }
     232                        else if ( matches.empty() ) {
     233                                // restore invalidated env
     234                                // newEnv = sat.cand->env;
     235                                // newNeed.clear();
    214236                                if ( auto c = commonType( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) {
    215237                                        // set up binding slot for recursive assertions
     
    220242                                        }
    221243
    222                                         matches.emplace_back(
     244                                        inexactMatches.emplace_back(
    223245                                                cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    224246                                                std::move( newOpen ), crntResnSlot );
    225247                                }
    226248                        }
    227                         else {
    228                                 if ( unifyExact( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true}, sat.symtab ) ) {
    229                                         // set up binding slot for recursive assertions
    230                                         ast::UniqueId crntResnSlot = 0;
    231                                         if ( ! newNeed.empty() ) {
    232                                                 crntResnSlot = ++globalResnSlot;
    233                                                 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; }
    234                                         }
    235 
    236                                         matches.emplace_back(
    237                                                 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    238                                                 std::move( newOpen ), crntResnSlot );
    239                                 }
    240                         }
    241249                }
    242250
    243251                // break if no satisfying match
     252                if ( matches.empty() ) matches = std::move(inexactMatches);
    244253                if ( matches.empty() ) return false;
    245254
     
    252261                // otherwise bind unique match in ongoing scope
    253262                AssnCandidate & match = matches.front();
    254                 addToSymbolTable( match.have, sat.symtab );
     263                // addToSymbolTable( match.have, sat.symtab );
    255264                sat.newNeed.insert( match.need.begin(), match.need.end() );
    256265                sat.cand->env = std::move( match.env );
     
    435444                // for each current mutually-compatible set of assertions
    436445                for ( SatState & sat : sats ) {
    437                         bool allowConversion = false;
    438446                        // stop this branch if a better option is already found
    439447                        auto it = thresholds.find( pruneKey( *sat.cand ) );
     
    448456                                for ( auto & assn : sat.need ) {
    449457                                        // fail early if any assertion is not satisfiable
    450                                         if ( ! satisfyAssertion( assn, sat, allowConversion, !next.empty() ) ) {
     458                                        if ( ! satisfyAssertion( assn, sat, !next.empty() ) ) {
    451459                                                next.emplace_back(assn);
    452460                                                // goto nextSat;
     
    457465                                // fail if nothing resolves
    458466                                else if (next.size() == sat.need.size()) {
    459                                         if (allowConversion) {
     467                                        // if (allowConversion) {
    460468                                                Indenter tabs{ 3 };
    461469                                                std::ostringstream ss;
     
    467475                                                errors.emplace_back( ss.str() );
    468476                                                goto nextSat;
    469                                         }
    470 
    471                                         else {
    472                                                 allowConversion = true;
    473                                                 continue;
    474                                         }
    475                                 }
    476                                 allowConversion = false;
     477                                        // }
     478
     479                                        // else {
     480                                        //      allowConversion = true;
     481                                        //      continue;
     482                                        // }
     483                                }
    477484                                sat.need = std::move(next);
    478485                        }
     
    528535                                                sat.cand->expr, std::move( compat.env ), std::move( compat.open ),
    529536                                                ast::AssertionSet{} /* need moved into satisfaction state */,
    530                                                 sat.cand->cost, sat.cand->cvtCost );
     537                                                sat.cand->cost );
    531538
    532539                                        ast::AssertionSet nextNewNeed{ sat.newNeed };
     
    541548                                        for ( DeferRef r : compat.assns ) {
    542549                                                AssnCandidate match = r.match;
    543                                                 addToSymbolTable( match.have, nextSymtab );
     550                                                // addToSymbolTable( match.have, nextSymtab );
    544551                                                nextNewNeed.insert( match.need.begin(), match.need.end() );
    545552
  • src/ResolvExpr/Unify.cc

    r1ab773e0 r46da46b  
    134134                env.apply( newSecond );
    135135
    136                 findOpenVars( newFirst, open, closed, need, have, FirstClosed );
    137                 findOpenVars( newSecond, open, closed, need, have, FirstOpen );
     136                // findOpenVars( newFirst, open, closed, need, have, FirstClosed );
     137                findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
    138138
    139139                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     
    10291029
    10301030                void postvisit( const ast::TypeInstType * typeInst ) {
    1031                         assert( open.find( *typeInst ) == open.end() );
     1031                        // assert( open.find( *typeInst ) == open.end() );
    10321032                        handleRefType( typeInst, type2 );
    10331033                }
     
    11421142        ) {
    11431143                ast::OpenVarSet closed;
    1144                 findOpenVars( type1, open, closed, need, have, FirstClosed );
    1145                 findOpenVars( type2, open, closed, need, have, FirstOpen );
     1144                // findOpenVars( type1, open, closed, need, have, FirstClosed );
     1145                findOpenVars( type2, open, closed, need, have, env, FirstOpen );
    11461146                return unifyInexact(
    11471147                        type1, type2, env, need, have, open, WidenMode{ true, true }, symtab, common );
     
    11601160                        entry1 = var1 ? open.find( *var1 ) : open.end(),
    11611161                        entry2 = var2 ? open.find( *var2 ) : open.end();
    1162                 bool isopen1 = entry1 != open.end();
    1163                 bool isopen2 = entry2 != open.end();
    1164 
     1162                // bool isopen1 = entry1 != open.end();
     1163                // bool isopen2 = entry2 != open.end();
     1164                bool isopen1 = var1 && env.lookup(*var1);
     1165                bool isopen2 = var2 && env.lookup(*var2);
     1166
     1167                /*
    11651168                if ( isopen1 && isopen2 ) {
    11661169                        if ( entry1->second.kind != entry2->second.kind ) return false;
     
    11721175                } else if ( isopen2 ) {
    11731176                        return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );
    1174                 } else {
     1177                } */
     1178                if ( isopen1 && isopen2 ) {
     1179                        if ( var1->base->kind != var2->base->kind ) return false;
     1180                        return env.bindVarToVar(
     1181                                var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
     1182                                open, widen, symtab );
     1183                } else if ( isopen1 ) {
     1184                        return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen, symtab );
     1185                } else if ( isopen2 ) {
     1186                        return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen, symtab );
     1187                }else {
    11751188                        return ast::Pass<Unify_new>::read(
    11761189                                type1, type2, env, need, have, open, widen, symtab );
    11771190                }
     1191               
    11781192        }
    11791193
  • src/SynTree/Expression.cc

    r1ab773e0 r46da46b  
    267267}
    268268
    269 CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {
     269CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated, CastKind kind ) : arg(arg), isGenerated( isGenerated ), kind( kind ) {
    270270        set_result(toType);
    271271}
    272272
    273 CastExpr::CastExpr( Expression * arg, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {
     273CastExpr::CastExpr( Expression * arg, bool isGenerated, CastKind kind ) : arg(arg), isGenerated( isGenerated ), kind( kind ) {
    274274        set_result( new VoidType( Type::Qualifiers() ) );
    275275}
    276276
    277 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) {
     277CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ), kind( other.kind ) {
    278278}
    279279
  • src/SynTree/Expression.h

    r1ab773e0 r46da46b  
    271271        bool isGenerated = true;
    272272
    273         CastExpr( Expression * arg, bool isGenerated = true );
    274         CastExpr( Expression * arg, Type * toType, bool isGenerated = true );
     273        enum CastKind {
     274                Default, // C
     275                Coerce, // reinterpret cast
     276                Return  // overload selection
     277        };
     278
     279        CastKind kind = Default;
     280
     281        CastExpr( Expression * arg, bool isGenerated = true, CastKind kind = Default );
     282        CastExpr( Expression * arg, Type * toType, bool isGenerated = true, CastKind kind = Default );
    275283        CastExpr( Expression * arg, void * ) = delete; // prevent accidentally passing pointers for isGenerated in the first constructor
    276284        CastExpr( const CastExpr & other );
  • src/Tuples/TupleAssignment.cc

    r1ab773e0 r46da46b  
    679679
    680680                                ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env );
     681                                finder.allowVoid = true;
    681682
    682683                                try {
Note: See TracChangeset for help on using the changeset viewer.