Changeset 21300d7


Ignore:
Timestamp:
Jun 12, 2019, 4:06:37 PM (2 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
arm-eh, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr
Children:
462a7c7, d60780c
Parents:
aaeacf4 (diff), 6625727 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
12 added
30 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/iostream.cfa

    raaeacf4 r21300d7  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // iostream.c --
     7// iostream.cfa --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jun  9 16:27:17 2019
    13 // Update Count     : 803
     12// Last Modified On : Wed Jun 12 15:00:31 2019
     13// Update Count     : 819
    1414//
    1515
     
    740740        } // ?|?
    741741
     742        istype & ?|?( istype & is, const char * fmt ) {
     743                fmt( is, fmt, "" );
     744                return is;
     745        } // ?|?
     746
     747        istype & ?|?( istype & is, char * s ) {
     748                fmt( is, "%s", s );
     749                return is;
     750        } // ?|?
     751
    742752        // manipulators
    743753        istype & ?|?( istype & is, istype & (* manip)( istype & ) ) {
     
    767777        // skip xxx
    768778        if ( ! f.s ) {
    769                 // printf( "skip %s\n", f.scanset );
    770                 fmt( is, f.scanset, "" );                                               // no input arguments
     779                //printf( "skip %s %d\n", f.scanset, f.wd );
     780                if ( f.wd != -1 ) for ( f.wd ) fmt( is, "%*c" ); // no input arguments
     781                else fmt( is, f.scanset, "" );
    771782                return is;
    772783        } // if
     
    797808} // ?|?
    798809
     810forall( dtype istype | istream( istype ) )
     811istype & ?|?( istype & is, _Istream_Char f ) {
     812        fmt( is, "%*c" );                                                                       // argument variable unused
     813        return is;
     814} // ?|?
     815
    799816#define InputFMTImpl( T, CODE ) \
    800817forall( dtype istype | istream( istype ) ) \
     
    802819        enum { size = 16 }; \
    803820        char fmtstr[size]; \
    804         if ( f.wd == -1 || strcmp( CODE, "c" ) == 0 ) { /* ignore width with "c" */     \
     821        if ( f.wd == -1 ) { \
    805822                snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \
    806823        } else { \
     
    812829} // ?|?
    813830
    814 InputFMTImpl( char, "c" )
    815831InputFMTImpl( signed char, "hhi" )
    816832InputFMTImpl( unsigned char, "hhi" )
  • libcfa/src/iostream.hfa

    raaeacf4 r21300d7  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jun  8 17:28:44 2019
    13 // Update Count     : 312
     12// Last Modified On : Wed Jun 12 13:35:42 2019
     13// Update Count     : 331
    1414//
    1515
     
    155155struct _Ostream_Manip {
    156156        T val;                                                                                          // polymorphic base-type
    157         unsigned char wd, pc;                                                           // width, precision
     157        unsigned int wd, pc;                                                            // width, precision
    158158        char base;                                                                                      // numeric base / floating-point style
    159159        union {
     
    180180        _Ostream_Manip(T) oct( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'o', { .all : 0 } }; } \
    181181        _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'x', { .all : 0 } }; } \
    182         _Ostream_Manip(T) wd( unsigned char w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, CODE, { .all : 0 } }; } \
    183         _Ostream_Manip(T) wd( unsigned char w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \
    184         _Ostream_Manip(T) & wd( unsigned char w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
    185         _Ostream_Manip(T) & wd( unsigned char w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
     182        _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, CODE, { .all : 0 } }; } \
     183        _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \
     184        _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
     185        _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    186186        _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
    187187        _Ostream_Manip(T) & upcase( _Ostream_Manip(T) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; } \
     
    190190        _Ostream_Manip(T) sign( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, CODE, { .flags.sign : true } }; } \
    191191        _Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \
    192 } \
     192} /* distribution */ \
    193193forall( dtype ostype | ostream( ostype ) ) { \
    194194        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
     
    214214        _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \
    215215        _Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \
    216         _Ostream_Manip(T) wd( unsigned char w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \
    217         _Ostream_Manip(T) wd( unsigned char w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
    218         _Ostream_Manip(T) ws( unsigned char w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
    219         _Ostream_Manip(T) & wd( unsigned char w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
    220         _Ostream_Manip(T) & wd( unsigned char w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
     216        _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \
     217        _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
     218        _Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
     219        _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
     220        _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    221221        _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
    222222        _Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \
     
    227227        _Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
    228228        _Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
    229 } \
     229} /* distribution */ \
    230230forall( dtype ostype | ostream( ostype ) ) { \
    231231        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
     
    239239
    240240static inline {
    241         _Ostream_Manip(char) bin( char val ) { return (_Ostream_Manip(char))@{ val, 1, 0, 'b', { .all : 0 } }; }
    242         _Ostream_Manip(char) oct( char val ) { return (_Ostream_Manip(char))@{ val, 1, 0, 'o', { .all : 0 } }; }
    243         _Ostream_Manip(char) hex( char val ) { return (_Ostream_Manip(char))@{ val, 1, 0, 'x', { .all : 0 } }; }
    244         _Ostream_Manip(char) wd( unsigned char w, char val ) { return (_Ostream_Manip(char))@{ val, w, 0, 'c', { .all : 0 } }; }
    245         _Ostream_Manip(char) & wd( unsigned char w, _Ostream_Manip(char) & fmt ) { fmt.wd = w; return fmt; }
     241        _Ostream_Manip(char) bin( char c ) { return (_Ostream_Manip(char))@{ c, 1, 0, 'b', { .all : 0 } }; }
     242        _Ostream_Manip(char) oct( char c ) { return (_Ostream_Manip(char))@{ c, 1, 0, 'o', { .all : 0 } }; }
     243        _Ostream_Manip(char) hex( char c ) { return (_Ostream_Manip(char))@{ c, 1, 0, 'x', { .all : 0 } }; }
     244        _Ostream_Manip(char) wd( unsigned int w, char c ) { return (_Ostream_Manip(char))@{ c, w, 0, 'c', { .all : 0 } }; }
     245        _Ostream_Manip(char) & wd( unsigned int w, _Ostream_Manip(char) & fmt ) { fmt.wd = w; return fmt; }
    246246        _Ostream_Manip(char) & left( _Ostream_Manip(char) & fmt ) { fmt.flags.left = true; return fmt; }
    247247        _Ostream_Manip(char) & upcase( _Ostream_Manip(char) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; }
     
    256256
    257257static inline {
    258         _Ostream_Manip(const char *) bin( const char * val ) { return (_Ostream_Manip(const char *))@{ val, 1, 0, 'b', { .all : 0 } }; }
    259         _Ostream_Manip(const char *) oct( const char * val ) { return (_Ostream_Manip(const char *))@{ val, 1, 0, 'o', { .all : 0 } }; }
    260         _Ostream_Manip(const char *) hex( const char * val ) { return (_Ostream_Manip(const char *))@{ val, 1, 0, 'x', { .all : 0 } }; }
    261         _Ostream_Manip(const char *) wd( unsigned char w, const char * val ) { return (_Ostream_Manip(const char *))@{ val, w, 0, 's', { .all : 0 } }; }
    262         _Ostream_Manip(const char *) wd( unsigned char w, unsigned char pc, const char * val ) { return (_Ostream_Manip(const char *))@{ val, w, pc, 's', { .flags.pc : true } }; }
    263         _Ostream_Manip(const char *) & wd( unsigned char w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
    264         _Ostream_Manip(const char *) & wd( unsigned char w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
     258        _Ostream_Manip(const char *) bin( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }
     259        _Ostream_Manip(const char *) oct( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }
     260        _Ostream_Manip(const char *) hex( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
     261        _Ostream_Manip(const char *) wd( unsigned int w, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
     262        _Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
     263        _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
     264        _Ostream_Manip(const char *) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
    265265        _Ostream_Manip(const char *) & left( _Ostream_Manip(const char *) & fmt ) { fmt.flags.left = true; return fmt; }
    266266        _Ostream_Manip(const char *) & nobase( _Ostream_Manip(const char *) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
     
    316316        istype & ?|?( istype &, long double _Complex & );
    317317
    318         // Cannot have char & and char * => cstr manipulator
    319         // istype & ?|?( istype &, char * );
     318        istype & ?|?( istype &, const char * );
     319        istype & ?|?( istype &, char * );
    320320
    321321        // manipulators
     
    341341}; // _Istream_Cstr
    342342
    343 static inline _Istream_Cstr skip( const char * scanset ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
    344 static inline _Istream_Cstr incl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
    345 static inline _Istream_Cstr incl( const char * scanset, _Istream_Cstr & fmt ) { fmt.flags.inex = false; return fmt; }
    346 static inline _Istream_Cstr excl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
    347 static inline _Istream_Cstr excl( const char * scanset, _Istream_Cstr & fmt ) { fmt.flags.inex = true; return fmt; }
    348 static inline _Istream_Cstr cstr( char * s ) { return (_Istream_Cstr){ s, 0p, -1, { .all : 0 } }; }
    349 static inline _Istream_Cstr ignore( const char * s ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
    350 static inline _Istream_Cstr ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; }
    351 static inline _Istream_Cstr wd( unsigned int w, char * s ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
    352 static inline _Istream_Cstr wd( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
    353 forall( dtype istype | istream( istype ) ) istype & ?|?( istype &, _Istream_Cstr );
     343static inline {
     344        _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
     345        _Istream_Cstr skip( const char * scanset ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
     346        _Istream_Cstr incl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
     347        _Istream_Cstr & incl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
     348        _Istream_Cstr excl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
     349        _Istream_Cstr & excl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
     350        _Istream_Cstr ignore( const char * s ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
     351        _Istream_Cstr & ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; }
     352        _Istream_Cstr wd( unsigned int w, char * s ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
     353        _Istream_Cstr & wd( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
     354} // distribution
     355forall( dtype istype | istream( istype ) ) istype & ?|?( istype & is, _Istream_Cstr f );
     356
     357struct _Istream_Char {
     358        bool ignore;                                                                            // do not change input argument
     359}; // _Istream_Char
     360
     361static inline {
     362        _Istream_Char ignore( const char c ) { return (_Istream_Char)@{ true }; }
     363        _Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; }
     364} // distribution
     365forall( dtype istype | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f );
    354366
    355367forall( otype T )
     
    361373
    362374#define InputFMTDecl( T ) \
    363 static inline _Istream_Manip(T) ignore( const T & val ) { return (_Istream_Manip(T))@{ (T &)val, -1, true }; } \
    364 static inline _Istream_Manip(T) ignore( _Istream_Manip(T) & fmt ) { fmt.ignore = true; return fmt; } \
    365 static inline _Istream_Manip(T) wd( unsigned int w, T & val ) { return (_Istream_Manip(T))@{ val, w, false }; } \
     375static inline { \
     376        _Istream_Manip(T) ignore( const T & val ) { return (_Istream_Manip(T))@{ (T &)val, -1, true }; } \
     377        _Istream_Manip(T) & ignore( _Istream_Manip(T) & fmt ) { fmt.ignore = true; return fmt; } \
     378        _Istream_Manip(T) wdi( unsigned int w, T & val ) { return (_Istream_Manip(T))@{ val, w, false }; } \
     379        _Istream_Manip(T) & wd( unsigned int w, _Istream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
     380} /* distribution */ \
    366381forall( dtype istype | istream( istype ) ) { \
    367382        istype & ?|?( istype & is, _Istream_Manip(T) f ); \
    368383} // ?|?
    369384
    370 InputFMTDecl( char )
    371385InputFMTDecl( signed char )
    372386InputFMTDecl( unsigned char )
  • src/AST/Convert.cpp

    raaeacf4 r21300d7  
    21932193
    21942194        int isStringlikeConstantType(const Type *t) {
     2195                const Type *referentType = nullptr;
    21952196                if ( const ArrayType * aty = dynamic_cast< const ArrayType * >( t ) ) {
    2196                         if ( const BasicType * bty = dynamic_cast< const BasicType * >( aty->base ) ) {
     2197                        referentType = aty->base;
     2198                } else if ( const PointerType * pty = dynamic_cast< const PointerType * >( t ) ) {
     2199                        referentType = pty->base;
     2200                }
     2201                if (referentType) {
     2202                        if ( const BasicType * bty = dynamic_cast< const BasicType * >( referentType ) ) {
    21972203                           if ( bty->kind == BasicType::Kind::Char ) {
    21982204                                   return true;
     
    22052211        virtual void visit( ConstantExpr * old ) override final {
    22062212                ast::ConstantExpr *rslt = nullptr;
    2207                 if (isIntlikeConstantType(old->result)) {
     2213                if (isStringlikeConstantType(old->result)) {
     2214                        rslt = new ast::ConstantExpr(
     2215                                old->location,
     2216                                GET_ACCEPT_1(result, Type),
     2217                                old->constant.get_value(),
     2218                                0,
     2219                                ast::ConstantExpr::Kind::String
     2220                        );
     2221                } else if (isIntlikeConstantType(old->result)) {
    22082222                        rslt = new ast::ConstantExpr(
    22092223                                old->location,
     
    22192233                                old->constant.get_value(),
    22202234                                (double) old->constant.get_dval()
    2221                         );
    2222                 } else if (isStringlikeConstantType(old->result)) {
    2223                         rslt = new ast::ConstantExpr(
    2224                                 old->location,
    2225                                 GET_ACCEPT_1(result, Type),
    2226                                 old->constant.get_value(),
    2227                                 0,
    2228                                 ast::ConstantExpr::Kind::String
    22292235                        );
    22302236                }
  • src/AST/Node.hpp

    raaeacf4 r21300d7  
    9999
    100100/// Mutate a node field (only clones if not equal to existing value)
    101 template<typename node_t, typename field_t>
    102 const node_t * mutate_field(
    103         const node_t * node,
    104         typename std::remove_const<typename std::remove_reference<field_t>::type>::type node_t::* field,
    105         field_t&& val
    106 ) {
     101template<typename node_t, typename field_t, typename assn_t>
     102const node_t * mutate_field( const node_t * node, field_t node_t::* field, assn_t && val ) {
     103        // skip mutate if equivalent
    107104        if ( node->*field == val ) return node;
    108105       
     106        // mutate and return
    109107        node_t * ret = mutate( node );
    110         ret->*field = std::forward< field_t >( val );
     108        ret->*field = std::forward< assn_t >( val );
     109        return ret;
     110}
     111
     112/// Mutate a single index of a node field (only clones if not equal to existing value)
     113template<typename node_t, typename coll_t, typename ind_t, typename field_t>
     114const node_t * mutate_field_index(
     115        const node_t * node, coll_t node_t::* field, ind_t i, field_t && val
     116) {
     117        // skip mutate if equivalent
     118        if  ( (node->*field)[i] == val ) return node;
     119
     120        // mutate and return
     121        node_t * ret = mutate( node );
     122        (ret->*field)[i] = std::forward< field_t >( val );
    111123        return ret;
    112124}
  • src/AST/Print.hpp

    raaeacf4 r21300d7  
    1616#pragma once
    1717
    18 #include <iosfwd>
    19 #include <utility> // for forward
     18#include <iostream>
     19#include <utility>   // for forward
    2020
    2121#include "AST/Node.hpp"
     
    3232void printShort( std::ostream & os, const ast::Decl * node, Indenter indent = {} );
    3333
    34 inline void printShort( std::ostream & os, const ast::Decl * node, unsigned int indent ) {
    35     printShort( os, node, Indenter{ indent } );
     34/// Print a collection of items
     35template< typename Coll >
     36void printAll( std::ostream & os, const Coll & c, Indenter indent = {} ) {
     37    for ( const auto & i : c ) {
     38        if ( ! i ) continue;
     39       
     40        os << indent;
     41        print( os, i, indent );
     42        os << std::endl;
     43    }
    3644}
    3745
  • src/AST/porting.md

    raaeacf4 r21300d7  
    299299* `openVars` => `open`
    300300
     301`ExplodedActual` => `ExplodedArg`
     302* `ExplodedActual.h` => `ExplodedArg.hpp`
     303
    301304[1] https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/Type-Attributes.html#Type-Attributes
    302305
  • src/InitTweak/InitTweak.cc

    raaeacf4 r21300d7  
     1//
     2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
     3//
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
     7// InitTweak.cc --
     8//
     9// Author           : Rob Schluntz
     10// Created On       : Fri May 13 11:26:36 2016
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 10 13:30:00 2019
     13// Update Count     : 5
     14//
     15
    116#include <algorithm>               // for find, all_of
    217#include <cassert>                 // for assertf, assert, strict_dynamic_cast
     
    419#include <iterator>                // for back_insert_iterator, back_inserter
    520#include <memory>                  // for __shared_ptr
     21#include <vector>
    622
    723#include "AST/Expr.hpp"
     
    307323        }
    308324
    309         struct CallFinder {
    310                 CallFinder( const std::list< std::string > & names ) : names( names ) {}
     325        struct CallFinder_old {
     326                CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
    311327
    312328                void postvisit( ApplicationExpr * appExpr ) {
     
    331347        };
    332348
     349        struct CallFinder_new final {
     350                std::vector< ast::ptr< ast::Expr > > matches;
     351                const std::vector< std::string > names;
     352
     353                CallFinder_new( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
     354
     355                void handleCallExpr( const ast::Expr * expr ) {
     356                        std::string fname = getFunctionName( expr );
     357                        if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
     358                                matches.emplace_back( expr );
     359                        }
     360                }
     361
     362                void postvisit( const ast::ApplicationExpr * expr ) { handleCallExpr( expr ); }
     363                void postvisit( const ast::UntypedExpr *     expr ) { handleCallExpr( expr ); }
     364        };
     365
    333366        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
    334                 static PassVisitor<CallFinder> finder( std::list< std::string >{ "?{}", "^?{}" } );
     367                static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } );
    335368                finder.pass.matches = &matches;
    336369                maybeAccept( stmt, finder );
     370        }
     371
     372        std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt ) {
     373                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
     374                maybe_accept( stmt, finder );
     375                return std::move( finder.pass.matches );
    337376        }
    338377
     
    436475        }
    437476
     477        const ast::ApplicationExpr * isIntrinsicCallExpr( const ast::Expr * expr ) {
     478                auto appExpr = dynamic_cast< const ast::ApplicationExpr * >( expr );
     479                if ( ! appExpr ) return nullptr;
     480
     481                const ast::DeclWithType * func = getCalledFunction( appExpr->func );
     482                assertf( func,
     483                        "getCalledFunction returned nullptr: %s", toString( appExpr->func ).c_str() );
     484               
     485                // check for Intrinsic only -- don't want to remove all overridable ctor/dtor because
     486                // autogenerated ctor/dtor will call all member dtors, and some members may have a
     487                // user-defined dtor
     488                return func->linkage == ast::Linkage::Intrinsic ? appExpr : nullptr;
     489        }
     490
    438491        namespace {
    439492                template <typename Predicate>
     
    444497                        return std::all_of( callExprs.begin(), callExprs.end(), pred);
    445498                }
     499
     500                template <typename Predicate>
     501                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
     502                        std::vector< ast::ptr< ast::Expr > > callExprs = collectCtorDtorCalls( stmt );
     503                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
     504                }
    446505        }
    447506
     
    452511                                assert( funcType );
    453512                                return funcType->get_parameters().size() == 1;
     513                        }
     514                        return false;
     515                });
     516        }
     517
     518        bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) {
     519                return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){
     520                        if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
     521                                const ast::FunctionType * funcType =
     522                                        GenPoly::getFunctionType( appExpr->func->result );
     523                                assert( funcType );
     524                                return funcType->params.size() == 1;
    454525                        }
    455526                        return false;
  • src/InitTweak/InitTweak.h

    raaeacf4 r21300d7  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // RemoveInit.h --
     7// InitTweak.h --
    88//
    99// Author           : Rob Schluntz
    1010// Created On       : Fri May 13 11:26:36 2016
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:30:33 2017
    13 // Update Count     : 4
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 10 13:30:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    1919#include <memory>             // for shared_ptr
    2020#include <string>             // for string, allocator
     21#include <vector>
    2122
    2223#include "AST/Fwd.hpp"        // for AST nodes
     
    6364        /// Non-Null if expr is a call expression whose target function is intrinsic
    6465        ApplicationExpr * isIntrinsicCallExpr( Expression * expr );
     66        const ast::ApplicationExpr * isIntrinsicCallExpr( const ast::Expr * expr);
    6567
    6668        /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
     
    6870        /// Currently has assertions that make it less than fully general.
    6971        bool isIntrinsicSingleArgCallStmt( Statement * stmt );
     72        bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
    7073
    7174        /// True if stmt is a call statement where the function called is intrinsic.
     
    7477        /// get all Ctor/Dtor call expressions from a Statement
    7578        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
     79        std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt );
    7680
    7781        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
  • src/Makefile.in

    raaeacf4 r21300d7  
    195195        ResolvExpr/CurrentObject.$(OBJEXT) \
    196196        ResolvExpr/ExplodedActual.$(OBJEXT) \
     197        ResolvExpr/ExplodedArg.$(OBJEXT) \
    197198        ResolvExpr/FindOpenVars.$(OBJEXT) ResolvExpr/Occurs.$(OBJEXT) \
    198199        ResolvExpr/PolyCost.$(OBJEXT) \
     
    203204        ResolvExpr/Resolver.$(OBJEXT) \
    204205        ResolvExpr/ResolveTypeof.$(OBJEXT) \
     206        ResolvExpr/SatisfyAssertions.$(OBJEXT) \
    205207        ResolvExpr/SpecCost.$(OBJEXT) \
    206208        ResolvExpr/TypeEnvironment.$(OBJEXT) \
     
    632634      ResolvExpr/CurrentObject.cc \
    633635      ResolvExpr/ExplodedActual.cc \
     636      ResolvExpr/ExplodedArg.cpp \
    634637      ResolvExpr/FindOpenVars.cc \
    635638      ResolvExpr/Occurs.cc \
     
    641644      ResolvExpr/Resolver.cc \
    642645      ResolvExpr/ResolveTypeof.cc \
     646      ResolvExpr/SatisfyAssertions.cpp \
    643647      ResolvExpr/SpecCost.cc \
    644648      ResolvExpr/TypeEnvironment.cc \
     
    893897ResolvExpr/ExplodedActual.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    894898        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     899ResolvExpr/ExplodedArg.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     900        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    895901ResolvExpr/FindOpenVars.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    896902        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     
    910916        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    911917ResolvExpr/ResolveTypeof.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     918        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     919ResolvExpr/SatisfyAssertions.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    912920        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    913921ResolvExpr/SpecCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     
    12731281@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/CurrentObject.Po@am__quote@
    12741282@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ExplodedActual.Po@am__quote@
     1283@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ExplodedArg.Po@am__quote@
    12751284@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/FindOpenVars.Po@am__quote@
    12761285@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/Occurs.Po@am__quote@
     
    12821291@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ResolveTypeof.Po@am__quote@
    12831292@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/Resolver.Po@am__quote@
     1293@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/SatisfyAssertions.Po@am__quote@
    12841294@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/SpecCost.Po@am__quote@
    12851295@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/TypeEnvironment.Po@am__quote@
  • src/ResolvExpr/AdjustExprType.cc

    raaeacf4 r21300d7  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // AdjustExprType.cc --
     7// AdjustExprType_old.cc --
    88//
    99// Author           : Richard C. Bilson
     
    1414//
    1515
     16#include "AST/Node.hpp"
     17#include "AST/Pass.hpp"
     18#include "AST/SymbolTable.hpp"
     19#include "AST/Type.hpp"
     20#include "AST/TypeEnvironment.hpp"
    1621#include "Common/PassVisitor.h"
    1722#include "SymTab/Indexer.h"       // for Indexer
     
    2227
    2328namespace ResolvExpr {
    24         class AdjustExprType : public WithShortCircuiting {
    25           public:
    26                 AdjustExprType( const TypeEnvironment & env, const SymTab::Indexer & indexer );
     29
     30namespace {
     31        class AdjustExprType_old final : public WithShortCircuiting {
     32                public:
     33                AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer );
    2734                void premutate( VoidType * ) { visit_children = false; }
    2835                void premutate( BasicType * ) { visit_children = false; }
     
    4451                Type * postmutate( TypeInstType *aggregateUseType );
    4552
    46           private:
     53                private:
    4754                const TypeEnvironment & env;
    4855                const SymTab::Indexer & indexer;
    4956        };
    5057
    51         void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    52                 PassVisitor<AdjustExprType> adjuster( env, indexer );
    53                 Type *newType = type->acceptMutator( adjuster );
    54                 type = newType;
    55         }
    56 
    57         void adjustExprType( Type *& type ) {
    58                 TypeEnvironment env;
    59                 SymTab::Indexer indexer;
    60                 adjustExprType( type, env, indexer );
    61         }
    62 
    63         AdjustExprType::AdjustExprType( const TypeEnvironment &env, const SymTab::Indexer &indexer )
     58        AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer )
    6459                : env( env ), indexer( indexer ) {
    6560        }
    6661
    67         Type * AdjustExprType::postmutate( ArrayType * arrayType ) {
     62        Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) {
    6863                PointerType *pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };
    6964                arrayType->base = nullptr;
     
    7267        }
    7368
    74         Type * AdjustExprType::postmutate( FunctionType * functionType ) {
     69        Type * AdjustExprType_old::postmutate( FunctionType * functionType ) {
    7570                return new PointerType{ Type::Qualifiers(), functionType };
    7671        }
    7772
    78         Type * AdjustExprType::postmutate( TypeInstType * typeInst ) {
     73        Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) {
    7974                if ( const EqvClass* eqvClass = env.lookup( typeInst->get_name() ) ) {
    8075                        if ( eqvClass->data.kind == TypeDecl::Ftype ) {
     
    9085                return typeInst;
    9186        }
     87} // anonymous namespace
     88
     89void 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
     95void adjustExprType( Type *& type ) {
     96        TypeEnvironment env;
     97        SymTab::Indexer indexer;
     98        adjustExprType( type, env, indexer );
     99}
     100
     101namespace {
     102        struct AdjustExprType_new final : public ast::WithShortCircuiting {
     103                const ast::TypeEnvironment & tenv;
     104                const ast::SymbolTable & symtab;
     105
     106                AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
     107                : tenv( e ), symtab( syms ) {}
     108
     109                void premutate( const ast::VoidType * ) { visit_children = false; }
     110                void premutate( const ast::BasicType * ) { visit_children = false; }
     111                void premutate( const ast::PointerType * ) { visit_children = false; }
     112                void premutate( const ast::ArrayType * ) { visit_children = false; }
     113                void premutate( const ast::FunctionType * ) { visit_children = false; }
     114                void premutate( const ast::StructInstType * ) { visit_children = false; }
     115                void premutate( const ast::UnionInstType * ) { visit_children = false; }
     116                void premutate( const ast::EnumInstType * ) { visit_children = false; }
     117                void premutate( const ast::TraitInstType * ) { visit_children = false; }
     118                void premutate( const ast::TypeInstType * ) { visit_children = false; }
     119                void premutate( const ast::TupleType * ) { visit_children = false; }
     120                void premutate( const ast::VarArgsType * ) { visit_children = false; }
     121                void premutate( const ast::ZeroType * ) { visit_children = false; }
     122                void premutate( const ast::OneType * ) { visit_children = false; }
     123
     124                const ast::Type * postmutate( const ast::ArrayType * at ) {
     125                        return new ast::PointerType{ at->base, at->qualifiers };
     126                }
     127
     128                const ast::Type * postmutate( const ast::FunctionType * ft ) {
     129                        return new ast::PointerType{ ft };
     130                }
     131
     132                const ast::Type * postmutate( const ast::TypeInstType * inst ) {
     133                        // replace known function-type-variables with pointer-to-function
     134                        if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
     135                                if ( eqvClass->data.kind == ast::TypeVar::Ftype ) {
     136                                        return new ast::PointerType{ inst };
     137                                }
     138                        } else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) {
     139                                if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) {
     140                                        if ( tyDecl->kind == ast::TypeVar::Ftype ) {
     141                                                return new ast::PointerType{ inst };
     142                                        }
     143                                }
     144                        }
     145                        return inst;
     146                }
     147        };
     148} // anonymous namespace
     149
     150const ast::Type * adjustExprType(
     151        const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
     152) {
     153        ast::Pass<AdjustExprType_new> adjuster{ env, symtab };
     154        return type->accept( adjuster );
     155}
     156
    92157} // namespace ResolvExpr
    93158
  • src/ResolvExpr/AlternativeFinder.cc

    raaeacf4 r21300d7  
    2929#include "AlternativeFinder.h"
    3030#include "AST/Expr.hpp"
     31#include "AST/SymbolTable.hpp"
    3132#include "AST/Type.hpp"
    3233#include "Common/SemanticError.h"  // for SemanticError
     
    115116                /// Finds matching alternatives for a function, given a set of arguments
    116117                template<typename OutputIterator>
    117                 void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
     118                void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs_old& args, OutputIterator out );
    118119                /// Sets up parameter inference for an output alternative
    119120                template< typename OutputIterator >
     
    266267                        SemanticError( expr, "No reasonable alternatives for expression " );
    267268                }
    268                 if ( mode.resolveAssns || mode.prune ) {
     269                if ( mode.satisfyAssns || mode.prune ) {
    269270                        // trim candidates just to those where the assertions resolve
    270271                        // - necessary pre-requisite to pruning
     
    592593
    593594                /// Gets the list of exploded alternatives for this pack
    594                 const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
     595                const ExplodedActual& getExpl( const ExplodedArgs_old& args ) const {
    595596                        return args[nextArg-1][explAlt];
    596597                }
     
    616617        /// Instantiates an argument to match a formal, returns false if no results left
    617618        bool instantiateArgument( Type* formalType, Initializer* initializer,
    618                         const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
     619                        const ExplodedArgs_old& args, std::vector<ArgPack>& results, std::size_t& genStart,
    619620                        const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
    620621                if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
     
    888889        template<typename OutputIterator>
    889890        void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
    890                         FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
     891                        FunctionType *funcType, const ExplodedArgs_old &args, OutputIterator out ) {
    891892                OpenVarSet funcOpenVars;
    892893                AssertionSet funcNeed, funcHave;
     
    10201021
    10211022                // pre-explode arguments
    1022                 ExplodedArgs argExpansions;
     1023                ExplodedArgs_old argExpansions;
    10231024                argExpansions.reserve( argAlternatives.size() );
    10241025
  • src/ResolvExpr/AlternativeFinder.h

    raaeacf4 r21300d7  
    3737        /// First index is which argument, second index is which alternative for that argument,
    3838        /// third index is which exploded element of that alternative
    39         using ExplodedArgs = std::vector< std::vector< ExplodedActual > >;
     39        using ExplodedArgs_old = std::vector< std::vector< ExplodedActual > >;
    4040
    4141        class AlternativeFinder {
  • src/ResolvExpr/Candidate.hpp

    raaeacf4 r21300d7  
    3030        /// A list of unresolved assertions
    3131        using AssertionList = std::vector<AssertionSet::value_type>;
     32
     33        /// Convenience to merge AssertionList into AssertionSet
     34        static inline void mergeAssertionSet( AssertionSet & dst, const AssertionList & src ) {
     35                for ( const auto & s : src ) { dst.emplace( s ); }
     36        }
    3237}
    3338
     
    4247        ast::OpenVarSet open;      ///< Open variables for environment
    4348        ast::AssertionList need;   ///< Assertions which need to be resolved
     49
     50        Candidate() : expr(), cost( Cost::zero ), cvtCost( Cost::zero ), env(), open(), need() {}
     51       
     52        Candidate( const ast::Expr * x, const ast::TypeEnvironment & e )
     53        : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {}
     54
     55        Candidate( const Candidate & o, const ast::Expr * x )
     56        : expr( x ), cost( o.cost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
     57          need( o.need ) {}
     58       
     59        Candidate(
     60                const ast::Expr * x, ast::TypeEnvironment && e, ast::OpenVarSet && o,
     61                ast::AssertionSet && n, const Cost & c )
     62        : expr( x ), cost( c ), cvtCost( Cost::zero ), env( std::move( e ) ), open( std::move( o ) ),
     63          need( n.begin(), n.end() ) {}
    4464};
    4565
     
    4969/// List of candidates
    5070using CandidateList = std::vector< CandidateRef >;
     71
     72/// Splice src after dst, clearing src
     73static inline void splice( CandidateList & dst, CandidateList & src ) {
     74        dst.reserve( dst.size() + src.size() );
     75        for ( CandidateRef & r : src ) { dst.emplace_back( std::move( r ) ); }
     76        src.clear();
     77}
     78
     79/// Splice src before dst
     80static inline void spliceBegin( CandidateList & dst, CandidateList & src ) {
     81        splice( src, dst );
     82        dst.swap( src );
     83}
     84
     85/// Sum the cost of a list of candidates
     86static inline Cost sumCost( const CandidateList & candidates ) {
     87        Cost total = Cost::zero;
     88        for ( const CandidateRef & r : candidates ) { total += r->cost; }
     89        return total;
     90}
     91
     92/// Holdover behaviour from old `findMinCost` -- xxx -- can maybe be eliminated?
     93static inline void promoteCvtCost( CandidateList & candidates ) {
     94        for ( CandidateRef & r : candidates ) {
     95                r->cost = r->cvtCost;
     96        }
     97}
    5198
    5299void print( std::ostream & os, const Candidate & cand, Indenter indent = {} );
  • src/ResolvExpr/CandidateFinder.cpp

    raaeacf4 r21300d7  
    1616#include "CandidateFinder.hpp"
    1717
     18#include <deque>
     19#include <iterator>               // for back_inserter
     20#include <sstream>
     21#include <string>
     22#include <unordered_map>
     23#include <vector>
     24
     25#include "Candidate.hpp"
     26#include "CompilationState.h"
     27#include "Cost.h"
     28#include "ExplodedArg.hpp"
     29#include "Resolver.h"
     30#include "SatisfyAssertions.hpp"
     31#include "typeops.h"              // for adjustExprType
     32#include "Unify.h"
    1833#include "AST/Expr.hpp"
     34#include "AST/Node.hpp"
     35#include "AST/Pass.hpp"
     36#include "AST/Print.hpp"
     37#include "AST/SymbolTable.hpp"
     38#include "AST/Type.hpp"
     39#include "SymTab/Mangler.h"
     40#include "Tuples/Tuples.h"        // for handleTupleAssignment
     41
     42#define PRINT( text ) if ( resolvep ) { text }
    1943
    2044namespace ResolvExpr {
    2145
     46namespace {
     47
     48        /// First index is which argument, second is which alternative, third is which exploded element
     49        using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
     50
     51        /// Returns a list of alternatives with the minimum cost in the given list
     52        CandidateList findMinCost( const CandidateList & candidates ) {
     53                CandidateList out;
     54                Cost minCost = Cost::infinity;
     55                for ( const CandidateRef & r : candidates ) {
     56                        if ( r->cost < minCost ) {
     57                                minCost = r->cost;
     58                                out.clear();
     59                                out.emplace_back( r );
     60                        } else if ( r->cost == minCost ) {
     61                                out.emplace_back( r );
     62                        }
     63                }
     64                return out;
     65        }
     66
     67        /// Computes conversion cost for a given candidate
     68        Cost computeApplicationConversionCost(
     69                const CandidateRef & cand, const ast::SymbolTable & symtab
     70        ) {
     71                #warning unimplemented
     72                (void)cand; (void)symtab;
     73                assert(false);
     74                return Cost::infinity;
     75        }
     76
     77        /// Actually visits expressions to find their candidate interpretations
     78        struct Finder final : public ast::WithShortCircuiting {
     79                CandidateFinder & selfFinder;
     80                const ast::SymbolTable & symtab;
     81                CandidateList & candidates;
     82                const ast::TypeEnvironment & tenv;
     83                ast::ptr< ast::Type > & targetType;
     84
     85                Finder( CandidateFinder & f )
     86                : selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),
     87                  targetType( f.targetType ) {}
     88               
     89                void previsit( const ast::Node * ) { visit_children = false; }
     90
     91                /// Convenience to add candidate to list
     92                template<typename... Args>
     93                void addCandidate( Args &&... args ) {
     94                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
     95                }
     96
     97                void postvisit( const ast::ApplicationExpr * applicationExpr ) {
     98                        addCandidate( applicationExpr, tenv );
     99                }
     100
     101                /// Builds a list of candidates for a function, storing them in out
     102                void makeFunctionCandidates(
     103                        const CandidateRef & func, const ast::FunctionType * funcType,
     104                        const ExplodedArgs_new & args, CandidateList & out
     105                ) {
     106                        #warning unimplemented
     107                        (void)func; (void)funcType; (void)args; (void)out;
     108                        assert(false);
     109                }
     110
     111                /// Adds implicit struct-conversions to the alternative list
     112                void addAnonConversions( const CandidateRef & cand ) {
     113                        #warning unimplemented
     114                        (void)cand;
     115                        assert(false);
     116                }
     117
     118                void postvisit( const ast::UntypedExpr * untypedExpr ) {
     119                        CandidateFinder funcFinder{ symtab, tenv };
     120                        funcFinder.find( untypedExpr->func, ResolvMode::withAdjustment() );
     121                        // short-circuit if no candidates
     122                        if ( funcFinder.candidates.empty() ) return;
     123
     124                        std::vector< CandidateFinder > argCandidates =
     125                                selfFinder.findSubExprs( untypedExpr->args );
     126                       
     127                        // take care of possible tuple assignments
     128                        // if not tuple assignment, handled as normal function call
     129                        Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
     130
     131                        // find function operators
     132                        ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" };
     133                        CandidateFinder opFinder{ symtab, tenv };
     134                        // okay if there aren't any function operations
     135                        opFinder.find( opExpr, ResolvMode::withoutFailFast() );
     136                        PRINT(
     137                                std::cerr << "known function ops:" << std::endl;
     138                                print( std::cerr, opFinder.candidates, 1 );
     139                        )
     140
     141                        // pre-explode arguments
     142                        ExplodedArgs_new argExpansions;
     143                        for ( const CandidateFinder & args : argCandidates ) {
     144                                argExpansions.emplace_back();
     145                                auto & argE = argExpansions.back();
     146                                for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
     147                        }
     148
     149                        // Find function matches
     150                        CandidateList found;
     151                        SemanticErrorException errors;
     152                        for ( CandidateRef & func : funcFinder ) {
     153                                try {
     154                                        PRINT(
     155                                                std::cerr << "working on alternative:" << std::endl;
     156                                                print( std::cerr, *func, 2 );
     157                                        )
     158
     159                                        // check if the type is a pointer to function
     160                                        const ast::Type * funcResult = func->expr->result->stripReferences();
     161                                        if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
     162                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     163                                                        CandidateRef newFunc{ new Candidate{ *func } };
     164                                                        newFunc->expr =
     165                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     166                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
     167                                                }
     168                                        } else if (
     169                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     170                                        ) {
     171                                                if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
     172                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
     173                                                                CandidateRef newFunc{ new Candidate{ *func } };
     174                                                                newFunc->expr =
     175                                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     176                                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     177                                                        }
     178                                                }
     179                                        }
     180                                } catch ( SemanticErrorException & e ) { errors.append( e ); }
     181                        }
     182
     183                        // Find matches on function operators `?()`
     184                        if ( ! opFinder.candidates.empty() ) {
     185                                // add exploded function alternatives to front of argument list
     186                                std::vector< ExplodedArg > funcE;
     187                                funcE.reserve( funcFinder.candidates.size() );
     188                                for ( const CandidateRef & func : funcFinder ) {
     189                                        funcE.emplace_back( *func, symtab );
     190                                }
     191                                argExpansions.emplace_front( std::move( funcE ) );
     192
     193                                for ( const CandidateRef & op : opFinder ) {
     194                                        try {
     195                                                // check if type is pointer-to-function
     196                                                const ast::Type * opResult = op->expr->result->stripReferences();
     197                                                if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
     198                                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     199                                                                CandidateRef newOp{ new Candidate{ *op} };
     200                                                                newOp->expr =
     201                                                                        referenceToRvalueConversion( newOp->expr, newOp->cost );
     202                                                                makeFunctionCandidates( newOp, function, argExpansions, found );
     203                                                        }
     204                                                }
     205                                        } catch ( SemanticErrorException & e ) { errors.append( e ); }
     206                                }
     207                        }
     208
     209                        // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     210                        // candidates
     211                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     212
     213                        // Compute conversion costs
     214                        for ( CandidateRef & withFunc : found ) {
     215                                Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
     216
     217                                PRINT(
     218                                        auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
     219                                        auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     220                                        auto function = pointer->base.strict_as< ast::FunctionType >();
     221                                       
     222                                        std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
     223                                        std::cerr << "parameters are:" << std::endl;
     224                                        ast::printAll( std::cerr, function->params, 2 );
     225                                        std::cerr << "arguments are:" << std::endl;
     226                                        ast::printAll( std::cerr, appExpr->args, 2 );
     227                                        std::cerr << "bindings are:" << std::endl;
     228                                        ast::print( std::cerr, withFunc->env, 2 );
     229                                        std::cerr << "cost is: " << withFunc->cost << std::endl;
     230                                        std::cerr << "cost of conversion is:" << cvtCost << std::endl;
     231                                )
     232
     233                                if ( cvtCost != Cost::infinity ) {
     234                                        withFunc->cvtCost = cvtCost;
     235                                        candidates.emplace_back( std::move( withFunc ) );
     236                                }
     237                        }
     238                        found = std::move( candidates );
     239
     240                        // use a new list so that candidates are not examined by addAnonConversions twice
     241                        CandidateList winners = findMinCost( found );
     242                        promoteCvtCost( winners );
     243
     244                        // function may return a struct/union value, in which case we need to add candidates
     245                        // for implicit conversions to each of the anonymous members, which must happen after
     246                        // `findMinCost`, since anon conversions are never the cheapest
     247                        for ( const CandidateRef & c : winners ) {
     248                                addAnonConversions( c );
     249                        }
     250                        spliceBegin( candidates, winners );
     251
     252                        if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
     253                                // If resolution is unsuccessful with a target type, try again without, since it
     254                                // will sometimes succeed when it wouldn't with a target type binding.
     255                                // For example:
     256                                //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
     257                                //   const char * x = "hello world";
     258                                //   unsigned char ch = x[0];
     259                                // Fails with simple return type binding (xxx -- check this!) as follows:
     260                                // * T is bound to unsigned char
     261                                // * (x: const char *) is unified with unsigned char *, which fails
     262                                // xxx -- fix this better
     263                                targetType = nullptr;
     264                                postvisit( untypedExpr );
     265                        }
     266                }
     267
     268                /// true if expression is an lvalue
     269                static bool isLvalue( const ast::Expr * x ) {
     270                        return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() );
     271                }
     272
     273                void postvisit( const ast::AddressExpr * addressExpr ) {
     274                        CandidateFinder finder{ symtab, tenv };
     275                        finder.find( addressExpr->arg );
     276                        for ( CandidateRef & r : finder.candidates ) {
     277                                if ( ! isLvalue( r->expr ) ) continue;
     278                                addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
     279                        }
     280                }
     281
     282                void postvisit( const ast::LabelAddressExpr * labelExpr ) {
     283                        addCandidate( labelExpr, tenv );
     284                }
     285
     286                void postvisit( const ast::CastExpr * castExpr ) {
     287                        #warning unimplemented
     288                        (void)castExpr;
     289                        assert(false);
     290                }
     291
     292                void postvisit( const ast::VirtualCastExpr * castExpr ) {
     293                        assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
     294                        CandidateFinder finder{ symtab, tenv };
     295                        // don't prune here, all alternatives guaranteed to have same type
     296                        finder.find( castExpr->arg, ResolvMode::withoutPrune() );
     297                        for ( CandidateRef & r : finder.candidates ) {
     298                                addCandidate(
     299                                        *r, new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
     300                        }
     301                }
     302
     303                void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
     304                        #warning unimplemented
     305                        (void)memberExpr;
     306                        assert(false);
     307                }
     308
     309                void postvisit( const ast::MemberExpr * memberExpr ) {
     310                        addCandidate( memberExpr, tenv );
     311                }
     312
     313                void postvisit( const ast::NameExpr * variableExpr ) {
     314                        #warning unimplemented
     315                        (void)variableExpr;
     316                        assert(false);
     317                }
     318
     319                void postvisit( const ast::VariableExpr * variableExpr ) {
     320                        // not sufficient to just pass `variableExpr` here, type might have changed since
     321                        // creation
     322                        addCandidate(
     323                                new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
     324                }
     325
     326                void postvisit( const ast::ConstantExpr * constantExpr ) {
     327                        addCandidate( constantExpr, tenv );
     328                }
     329
     330                void postvisit( const ast::SizeofExpr * sizeofExpr ) {
     331                        #warning unimplemented
     332                        (void)sizeofExpr;
     333                        assert(false);
     334                }
     335
     336                void postvisit( const ast::AlignofExpr * alignofExpr ) {
     337                        #warning unimplemented
     338                        (void)alignofExpr;
     339                        assert(false);
     340                }
     341
     342                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
     343                        #warning unimplemented
     344                        (void)offsetofExpr;
     345                        assert(false);
     346                }
     347
     348                void postvisit( const ast::OffsetofExpr * offsetofExpr ) {
     349                        addCandidate( offsetofExpr, tenv );
     350                }
     351
     352                void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
     353                        addCandidate( offsetPackExpr, tenv );
     354                }
     355
     356                void postvisit( const ast::LogicalExpr * logicalExpr ) {
     357                        CandidateFinder finder1{ symtab, tenv };
     358                        finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
     359                        if ( finder1.candidates.empty() ) return;
     360
     361                        CandidateFinder finder2{ symtab, tenv };
     362                        finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
     363                        if ( finder2.candidates.empty() ) return;
     364
     365                        for ( const CandidateRef & r1 : finder1.candidates ) {
     366                                for ( const CandidateRef & r2 : finder2.candidates ) {
     367                                        ast::TypeEnvironment env{ r1->env };
     368                                        env.simpleCombine( r2->env );
     369                                        ast::OpenVarSet open{ r1->open };
     370                                        mergeOpenVars( open, r2->open );
     371                                        ast::AssertionSet need;
     372                                        mergeAssertionSet( need, r1->need );
     373                                        mergeAssertionSet( need, r2->need );
     374
     375                                        addCandidate(
     376                                                new ast::LogicalExpr{
     377                                                        logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
     378                                                std::move( env ), std::move( open ), std::move( need ),
     379                                                r1->cost + r2->cost );
     380                                }
     381                        }
     382                }
     383
     384                void postvisit( const ast::ConditionalExpr * conditionalExpr ) {
     385                        // candidates for condition
     386                        CandidateFinder finder1{ symtab, tenv };
     387                        finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
     388                        if ( finder1.candidates.empty() ) return;
     389
     390                        // candidates for true result
     391                        CandidateFinder finder2{ symtab, tenv };
     392                        finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
     393                        if ( finder2.candidates.empty() ) return;
     394
     395                        // candidates for false result
     396                        CandidateFinder finder3{ symtab, tenv };
     397                        finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
     398                        if ( finder3.candidates.empty() ) return;
     399
     400                        for ( const CandidateRef & r1 : finder1.candidates ) {
     401                                for ( const CandidateRef & r2 : finder2.candidates ) {
     402                                        for ( const CandidateRef & r3 : finder3.candidates ) {
     403                                                ast::TypeEnvironment env{ r1->env };
     404                                                env.simpleCombine( r2->env );
     405                                                env.simpleCombine( r3->env );
     406                                                ast::OpenVarSet open{ r1->open };
     407                                                mergeOpenVars( open, r2->open );
     408                                                mergeOpenVars( open, r3->open );
     409                                                ast::AssertionSet need;
     410                                                mergeAssertionSet( need, r1->need );
     411                                                mergeAssertionSet( need, r2->need );
     412                                                mergeAssertionSet( need, r3->need );
     413                                                ast::AssertionSet have;
     414
     415                                                // unify true and false results, then infer parameters to produce new
     416                                                // candidates
     417                                                ast::ptr< ast::Type > common;
     418                                                if (
     419                                                        unify(
     420                                                                r2->expr->result, r3->expr->result, env, need, have, open, symtab,
     421                                                                common )
     422                                                ) {
     423                                                        #warning unimplemented
     424                                                        assert(false);
     425                                                }
     426                                        }
     427                                }
     428                        }
     429                }
     430
     431                void postvisit( const ast::CommaExpr * commaExpr ) {
     432                        ast::TypeEnvironment env{ tenv };
     433                        ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
     434                       
     435                        CandidateFinder finder2{ symtab, env };
     436                        finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     437
     438                        for ( const CandidateRef & r2 : finder2.candidates ) {
     439                                addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
     440                        }
     441                }
     442
     443                void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
     444                        addCandidate( ctorExpr, tenv );
     445                }
     446
     447                void postvisit( const ast::ConstructorExpr * ctorExpr ) {
     448                        CandidateFinder finder{ symtab, tenv };
     449                        finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
     450                        for ( CandidateRef & r : finder.candidates ) {
     451                                addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
     452                        }
     453                }
     454
     455                void postvisit( const ast::RangeExpr * rangeExpr ) {
     456                        // resolve low and high, accept candidates where low and high types unify
     457                        CandidateFinder finder1{ symtab, tenv };
     458                        finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
     459                        if ( finder1.candidates.empty() ) return;
     460
     461                        CandidateFinder finder2{ symtab, tenv };
     462                        finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
     463                        if ( finder2.candidates.empty() ) return;
     464
     465                        for ( const CandidateRef & r1 : finder1.candidates ) {
     466                                for ( const CandidateRef & r2 : finder2.candidates ) {
     467                                        ast::TypeEnvironment env{ r1->env };
     468                                        env.simpleCombine( r2->env );
     469                                        ast::OpenVarSet open{ r1->open };
     470                                        mergeOpenVars( open, r2->open );
     471                                        ast::AssertionSet need;
     472                                        mergeAssertionSet( need, r1->need );
     473                                        mergeAssertionSet( need, r2->need );
     474                                        ast::AssertionSet have;
     475
     476                                        ast::ptr< ast::Type > common;
     477                                        if (
     478                                                unify(
     479                                                        r1->expr->result, r2->expr->result, env, need, have, open, symtab,
     480                                                        common )
     481                                        ) {
     482                                                ast::RangeExpr * newExpr =
     483                                                        new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
     484                                                newExpr->result = common ? common : r1->expr->result;
     485                                               
     486                                                #warning unimplemented
     487                                                assert(false);
     488                                        }
     489                                }
     490                        }
     491                }
     492
     493                void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
     494                        std::vector< CandidateFinder > subCandidates =
     495                                selfFinder.findSubExprs( tupleExpr->exprs );
     496                        std::vector< CandidateList > possibilities;
     497                        combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
     498
     499                        for ( const CandidateList & subs : possibilities ) {
     500                                std::vector< ast::ptr< ast::Expr > > exprs;
     501                                exprs.reserve( subs.size() );
     502                                for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
     503
     504                                ast::TypeEnvironment env;
     505                                ast::OpenVarSet open;
     506                                ast::AssertionSet need;
     507                                for ( const CandidateRef & sub : subs ) {
     508                                        env.simpleCombine( sub->env );
     509                                        mergeOpenVars( open, sub->open );
     510                                        mergeAssertionSet( need, sub->need );
     511                                }
     512
     513                                addCandidate(
     514                                        new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
     515                                        std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
     516                        }
     517                }
     518
     519                void postvisit( const ast::TupleExpr * tupleExpr ) {
     520                        addCandidate( tupleExpr, tenv );
     521                }
     522
     523                void postvisit( const ast::TupleIndexExpr * tupleExpr ) {
     524                        addCandidate( tupleExpr, tenv );
     525                }
     526
     527                void postvisit( const ast::TupleAssignExpr * tupleExpr ) {
     528                        addCandidate( tupleExpr, tenv );
     529                }
     530
     531                void postvisit( const ast::UniqueExpr * unqExpr ) {
     532                        CandidateFinder finder{ symtab, tenv };
     533                        finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
     534                        for ( CandidateRef & r : finder.candidates ) {
     535                                // ensure that the the id is passed on so that the expressions are "linked"
     536                                addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
     537                        }
     538                }
     539
     540                void postvisit( const ast::StmtExpr * stmtExpr ) {
     541                        #warning unimplemented
     542                        (void)stmtExpr;
     543                        assert(false);
     544                }
     545
     546                void postvisit( const ast::UntypedInitExpr * initExpr ) {
     547                        #warning unimplemented
     548                        (void)initExpr;
     549                        assert(false);
     550                }
     551
     552                void postvisit( const ast::InitExpr * ) {
     553                        assertf( false, "CandidateFinder should never see a resolved InitExpr." );
     554                }
     555
     556                void postvisit( const ast::DeletedExpr * ) {
     557                        assertf( false, "CandidateFinder should never see a DeletedExpr." );
     558                }
     559
     560                void postvisit( const ast::GenericExpr * ) {
     561                        assertf( false, "_Generic is not yet supported." );
     562                }
     563        };
     564
     565        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     566        /// return type. Skips ambiguous candidates.
     567        CandidateList pruneCandidates( CandidateList & candidates ) {
     568                struct PruneStruct {
     569                        CandidateRef candidate;
     570                        bool ambiguous;
     571
     572                        PruneStruct() = default;
     573                        PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
     574                };
     575
     576                // find lowest-cost candidate for each type
     577                std::unordered_map< std::string, PruneStruct > selected;
     578                for ( CandidateRef & candidate : candidates ) {
     579                        std::string mangleName;
     580                        {
     581                                ast::ptr< ast::Type > newType = candidate->expr->result;
     582                                candidate->env.apply( newType );
     583                                mangleName = Mangle::mangle( newType );
     584                        }
     585
     586                        auto found = selected.find( mangleName );
     587                        if ( found != selected.end() ) {
     588                                if ( candidate->cost < found->second.candidate->cost ) {
     589                                        PRINT(
     590                                                std::cerr << "cost " << candidate->cost << " beats "
     591                                                        << found->second.candidate->cost << std::endl;
     592                                        )
     593
     594                                        found->second = PruneStruct{ candidate };
     595                                } else if ( candidate->cost == found->second.candidate->cost ) {
     596                                        // if one of the candidates contains a deleted identifier, can pick the other,
     597                                        // since deleted expressions should not be ambiguous if there is another option
     598                                        // that is at least as good
     599                                        if ( findDeletedExpr( candidate->expr ) ) {
     600                                                // do nothing
     601                                                PRINT( std::cerr << "candidate is deleted" << std::endl; )
     602                                        } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
     603                                                PRINT( std::cerr << "current is deleted" << std::endl; )
     604                                                found->second = PruneStruct{ candidate };
     605                                        } else {
     606                                                PRINT( std::cerr << "marking ambiguous" << std::endl; )
     607                                                found->second.ambiguous = true;
     608                                        }
     609                                } else {
     610                                        PRINT(
     611                                                std::cerr << "cost " << candidate->cost << " loses to "
     612                                                        << found->second.candidate->cost << std::endl;
     613                                        )
     614                                }
     615                        } else {
     616                                selected.emplace_hint( found, mangleName, candidate );
     617                        }
     618                }
     619
     620                // report unambiguous min-cost candidates
     621                CandidateList out;
     622                for ( auto & target : selected ) {
     623                        if ( target.second.ambiguous ) continue;
     624
     625                        CandidateRef cand = target.second.candidate;
     626                       
     627                        ast::ptr< ast::Type > newResult = cand->expr->result;
     628                        cand->env.applyFree( newResult );
     629                        cand->expr = ast::mutate_field(
     630                                cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
     631                       
     632                        out.emplace_back( cand );
     633                }
     634                return out;
     635        }
     636
     637} // anonymous namespace
     638
    22639void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
    23         #warning unimplemented
    24         (void)expr; (void)mode;
    25         assert(false);
     640        // Find alternatives for expression
     641        ast::Pass<Finder> finder{ *this };
     642        expr->accept( finder );
     643
     644        if ( mode.failFast && candidates.empty() ) {
     645                SemanticError( expr, "No reasonable alternatives for expression " );
     646        }
     647
     648        if ( mode.satisfyAssns || mode.prune ) {
     649                // trim candidates to just those where the assertions are satisfiable
     650                // - necessary pre-requisite to pruning
     651                CandidateList satisfied;
     652                std::vector< std::string > errors;
     653                for ( auto & candidate : candidates ) {
     654                        satisfyAssertions( *candidate, symtab, satisfied, errors );
     655                }
     656
     657                // fail early if none such
     658                if ( mode.failFast && satisfied.empty() ) {
     659                        std::ostringstream stream;
     660                        stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     661                        for ( const auto& err : errors ) {
     662                                stream << err;
     663                        }
     664                        SemanticError( expr->location, stream.str() );
     665                }
     666
     667                // reset candidates
     668                candidates = std::move( satisfied );
     669        }
     670
     671        if ( mode.prune ) {
     672                // trim candidates to single best one
     673                PRINT(
     674                        std::cerr << "alternatives before prune:" << std::endl;
     675                        print( std::cerr, candidates );
     676                )
     677
     678                CandidateList pruned = pruneCandidates( candidates );
     679               
     680                if ( mode.failFast && pruned.empty() ) {
     681                        std::ostringstream stream;
     682                        CandidateList winners = findMinCost( candidates );
     683                        stream << "Cannot choose between " << winners.size() << " alternatives for "
     684                                "expression\n";
     685                        ast::print( stream, expr );
     686                        stream << " Alternatives are:\n";
     687                        print( stream, winners, 1 );
     688                        SemanticError( expr->location, stream.str() );
     689                }
     690
     691                auto oldsize = candidates.size();
     692                candidates = std::move( pruned );
     693
     694                PRINT(
     695                        std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
     696                )
     697                PRINT(
     698                        std::cerr << "there are " << candidates.size() << " alternatives after elimination"
     699                                << std::endl;
     700                )
     701        }
     702
     703        // adjust types after pruning so that types substituted by pruneAlternatives are correctly
     704        // adjusted
     705        if ( mode.adjust ) {
     706                for ( CandidateRef & r : candidates ) {
     707                        r->expr = ast::mutate_field(
     708                                r->expr.get(), &ast::Expr::result,
     709                                adjustExprType( r->expr->result, r->env, symtab ) );
     710                }
     711        }
     712
     713        // Central location to handle gcc extension keyword, etc. for all expressions
     714        for ( CandidateRef & r : candidates ) {
     715                if ( r->expr->extension != expr->extension ) {
     716                        r->expr.get_and_mutate()->extension = expr->extension;
     717                }
     718        }
     719}
     720
     721std::vector< CandidateFinder > CandidateFinder::findSubExprs(
     722        const std::vector< ast::ptr< ast::Expr > > & xs
     723) {
     724        std::vector< CandidateFinder > out;
     725
     726        for ( const auto & x : xs ) {
     727                out.emplace_back( symtab, env );
     728                out.back().find( x, ResolvMode::withAdjustment() );
     729               
     730                PRINT(
     731                        std::cerr << "findSubExprs" << std::endl;
     732                        print( std::cerr, out.back().candidates );
     733                )
     734        }
     735
     736        return out;
    26737}
    27738
  • src/ResolvExpr/CandidateFinder.hpp

    raaeacf4 r21300d7  
    1919#include "ResolvMode.h"
    2020#include "AST/Fwd.hpp"
     21#include "AST/Node.hpp"
    2122#include "AST/SymbolTable.hpp"
    2223#include "AST/TypeEnvironment.hpp"
     
    2930        const ast::SymbolTable & symtab;         ///< Symbol table to lookup candidates
    3031        const ast::TypeEnvironment & env;        ///< Substitutions performed in this resolution
    31         const ast::Type * targetType = nullptr;  ///< Target type for resolution
     32        ast::ptr< ast::Type > targetType = nullptr;  ///< Target type for resolution
    3233
    3334        CandidateFinder( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
     
    3637        /// Fill candidates with feasible resolutions for `expr`
    3738        void find( const ast::Expr * expr, ResolvMode mode = {} );
     39
     40        /// Runs new candidate finder on each element in xs, returning the list of finders
     41        std::vector< CandidateFinder > findSubExprs( const std::vector< ast::ptr< ast::Expr > > & xs );
     42
     43        using value_type = CandidateList::value_type;
     44        using iterator = CandidateList::iterator;
     45        using const_iterator = CandidateList::const_iterator;
     46
     47        iterator begin() { return candidates.begin(); }
     48        const_iterator begin() const { return candidates.begin(); }
     49       
     50        iterator end() { return candidates.end(); }
     51        const_iterator end() const { return candidates.end(); }
    3852};
    3953
  • src/ResolvExpr/CurrentObject.cc

    raaeacf4 r21300d7  
    946946        }
    947947
    948         void CurrentObject::setNext( const ast::Designation * designation ) {
     948        const Designation * CurrentObject::findNext( const Designation * designation ) {
     949                using DesignatorChain = std::deque< ptr< Expr > >;
     950                PRINT( std::cerr << "___findNext" << std::endl; )
     951               
     952                // find all the d's
     953                std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
     954                std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes;
     955                for ( const Expr * expr : designation->designators ) {
     956                        PRINT( std::cerr << "____untyped: " << expr << std::endl; )
     957                        auto dit = desigAlts.begin();
     958                        if ( auto nexpr = dynamic_cast< const NameExpr * >( expr ) ) {
     959                                for ( const Type * t : curTypes ) {
     960                                        assert( dit != desigAlts.end() );
     961
     962                                        DesignatorChain & d = *dit;
     963                                        PRINT( std::cerr << "____actual: " << t << std::endl; )
     964                                        if ( auto refType = dynamic_cast< const ReferenceToType * >( t ) ) {
     965                                                // concatenate identical field names
     966                                                for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
     967                                                        if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
     968                                                                PRINT( std::cerr << "____alt: " << field->type << std::endl; )
     969                                                                DesignatorChain d2 = d;
     970                                                                d2.emplace_back( new VariableExpr{ expr->location, field } );
     971                                                                newDesigAlts.emplace_back( std::move( d2 ) );
     972                                                                newTypes.emplace_back( field->type );
     973                                                        }
     974                                                }
     975                                        }
     976
     977                                        ++dit;
     978                                }
     979                        } else {
     980                                for ( const Type * t : curTypes ) {
     981                                        assert( dit != desigAlts.end() );
     982
     983                                        DesignatorChain & d = *dit;
     984                                        if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
     985                                                PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
     986                                                d.emplace_back( expr );
     987                                                newDesigAlts.emplace_back( d );
     988                                                newTypes.emplace_back( at->base );
     989                                        }
     990                                }
     991                        }
     992
     993                        // reset queue
     994                        desigAlts = std::move( newDesigAlts );
     995                        newDesigAlts.clear();
     996                        curTypes = std::move( newTypes );
     997                        newTypes.clear();
     998                        assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
     999                }
     1000
     1001                if ( desigAlts.size() > 1 ) {
     1002                        SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
     1003                } else if ( desigAlts.empty() ) {
     1004                        SemanticError( designation, "No reasonable alternatives for designation: " );
     1005                }
     1006
     1007                DesignatorChain & d = desigAlts.back();
     1008                PRINT( for ( Expression * expr : d ) {
     1009                        std::cerr << "____desig: " << expr << std::endl;
     1010                } ) // for
     1011                assertf( ! curTypes.empty(), "empty designator chosen");
     1012
     1013                // set new designators
     1014                assertf( ! objStack.empty(), "empty object stack when setting designation" );
     1015                Designation * actualDesignation =
     1016                        new Designation{ designation->location, DesignatorChain{d} };
     1017                objStack.back()->setPosition( d ); // destroys d
     1018                return actualDesignation;
     1019        }
     1020
     1021        void CurrentObject::setNext( const Designation * designation ) {
    9491022                PRINT( std::cerr << "____setNext" << designation << std::endl; )
    9501023                assertf( ! objStack.empty(), "obj stack empty in setNext" );
  • src/ResolvExpr/CurrentObject.h

    raaeacf4 r21300d7  
    111111                CurrentObject( const CodeLocation & loc, const Type * type );
    112112
     113                /// resolves unresolved designation
     114                const Designation * findNext( const Designation * designation );
    113115                /// sets current position using the resolved designation
    114116                void setNext( const ast::Designation * designation );
  • src/ResolvExpr/ExplodedActual.cc

    raaeacf4 r21300d7  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Alternative.h --
     7// ExplodedActual.cc --
    88//
    99// Author           : Aaron B. Moss
     
    2424        }
    2525}
     26
     27// Local Variables: //
     28// tab-width: 4 //
     29// mode: c++ //
     30// compile-command: "make install" //
     31// End: //
  • src/ResolvExpr/ExplodedActual.h

    raaeacf4 r21300d7  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Alternative.h --
     7// ExplodedActual.h --
    88//
    99// Author           : Aaron B. Moss
     
    3737        };
    3838}
     39
     40// Local Variables: //
     41// tab-width: 4 //
     42// mode: c++ //
     43// compile-command: "make install" //
     44// End: //
  • src/ResolvExpr/ResolvMode.h

    raaeacf4 r21300d7  
    2222                const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
    2323                const bool failFast;         ///< Fail on no resulting alternatives? [true]
    24                 const bool resolveAssns;     ///< Resolve assertions? [false]
     24                const bool satisfyAssns;     ///< Satisfy assertions? [false]
    2525
    2626        private:
    27                 constexpr ResolvMode(bool a, bool p, bool ff, bool ra)
    28                 : adjust(a), prune(p), failFast(ff), resolveAssns(ra) {}
     27                constexpr ResolvMode(bool a, bool p, bool ff, bool sa)
     28                : adjust(a), prune(p), failFast(ff), satisfyAssns(sa) {}
    2929
    3030        public:
    3131                /// Default settings
    32                 constexpr ResolvMode() : adjust(false), prune(true), failFast(true), resolveAssns(false) {}
     32                constexpr ResolvMode() : adjust(false), prune(true), failFast(true), satisfyAssns(false) {}
    3333               
    3434                /// With adjust flag set; turns array and function types into equivalent pointers
     
    4343                static constexpr ResolvMode withoutFailFast() { return { true, true, false, false }; }
    4444
    45                 /// The same mode, but with resolveAssns turned on; for top-level calls
     45                /// The same mode, but with satisfyAssns turned on; for top-level calls
    4646                ResolvMode atTopLevel() const { return { adjust, prune, failFast, true }; }
    4747        };
  • src/ResolvExpr/Resolver.cc

    raaeacf4 r21300d7  
    3535#include "AST/Print.hpp"
    3636#include "AST/SymbolTable.hpp"
     37#include "AST/Type.hpp"
    3738#include "Common/PassVisitor.h"          // for PassVisitor
    3839#include "Common/SemanticError.h"        // for SemanticError
     
    956957                        }
    957958                };
    958 
    959                 /// Check if this expression is or includes a deleted expression
    960                 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
    961                         ast::Pass<DeleteFinder_new> finder;
    962                         expr->accept( finder );
    963                         return finder.pass.delExpr;
    964                 }
    965 
     959        } // anonymous namespace
     960
     961        /// Check if this expression is or includes a deleted expression
     962        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
     963                ast::Pass<DeleteFinder_new> finder;
     964                expr->accept( finder );
     965                return finder.pass.delExpr;
     966        }
     967
     968        namespace {
    966969                /// always-accept candidate filter
    967970                bool anyCandidate( const Candidate & ) { return true; }
     
    10231026
    10241027                        // promote candidate.cvtCost to .cost
    1025                         for ( CandidateRef & cand : winners ) {
    1026                                 cand->cost = cand->cvtCost;
    1027                         }
     1028                        promoteCvtCost( winners );
    10281029
    10291030                        // produce ambiguous errors, if applicable
     
    10991100                        StripCasts_new::strip( expr );
    11001101                }
    1101 
    1102                 /// Find the expression candidate that is the unique best match for `untyped` in a `void`
    1103                 /// context.
    1104                 ast::ptr< ast::Expr > resolveInVoidContext(
    1105                         const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env
    1106                 ) {
    1107                         assertf( expr, "expected a non-null expression" );
    1108                        
    1109                         // set up and resolve expression cast to void
    1110                         ast::CastExpr * untyped = new ast::CastExpr{ expr->location, expr };
    1111                         CandidateRef choice = findUnfinishedKindExpression(
    1112                                 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
    1113                        
    1114                         // a cast expression has either 0 or 1 interpretations (by language rules);
    1115                         // if 0, an exception has already been thrown, and this code will not run
    1116                         const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
    1117                         env = std::move( choice->env );
    1118 
    1119                         return castExpr->arg;
    1120                 }
    1121 
     1102        } // anonymous namespace
     1103
     1104               
     1105        ast::ptr< ast::Expr > resolveInVoidContext(
     1106                const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env
     1107        ) {
     1108                assertf( expr, "expected a non-null expression" );
     1109               
     1110                // set up and resolve expression cast to void
     1111                ast::CastExpr * untyped = new ast::CastExpr{ expr->location, expr };
     1112                CandidateRef choice = findUnfinishedKindExpression(
     1113                        untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
     1114               
     1115                // a cast expression has either 0 or 1 interpretations (by language rules);
     1116                // if 0, an exception has already been thrown, and this code will not run
     1117                const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
     1118                env = std::move( choice->env );
     1119
     1120                return castExpr->arg;
     1121        }
     1122
     1123        namespace {
    11221124                /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
    11231125                /// context.
     
    11461148                }
    11471149
     1150                /// Resolve `untyped` to the single expression whose candidate is the best match
     1151                ast::ptr< ast::Expr > findSingleExpression(
     1152                        const ast::Expr * untyped, const ast::SymbolTable & symtab
     1153                ) {
     1154                        return findKindExpression( untyped, symtab );
     1155                }
     1156
    11481157                /// Resolve `untyped` to the single expression whose candidate is the best match for the
    11491158                /// given type.
     
    11521161                ) {
    11531162                        assert( untyped && type );
    1154                         const ast::Expr * castExpr = new ast::CastExpr{ untyped->location, untyped, type };
    1155                         ast::ptr< ast::Expr > newExpr = findKindExpression( castExpr, symtab );
     1163                        ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped->location, untyped, type };
     1164                        ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
    11561165                        removeExtraneousCast( newExpr, symtab );
    11571166                        return newExpr;
     
    11891198                        return false;
    11901199                }
     1200
     1201                /// Advance a type itertor to the next mutex parameter
     1202                template<typename Iter>
     1203                inline bool nextMutex( Iter & it, const Iter & end ) {
     1204                        while ( it != end && ! (*it)->get_type()->is_mutex() ) { ++it; }
     1205                        return it != end;
     1206                }
    11911207        }
    11921208
     
    12131229                void previsit( const ast::PointerType * );
    12141230
    1215                 const ast::ExprStmt *   previsit( const ast::ExprStmt * );
    1216                 const ast::AsmExpr *    previsit( const ast::AsmExpr * );
    1217                 const ast::AsmStmt *    previsit( const ast::AsmStmt * );
    1218                 const ast::IfStmt *     previsit( const ast::IfStmt * );
    1219                 const ast::WhileStmt *  previsit( const ast::WhileStmt * );
    1220                 const ast::ForStmt *    previsit( const ast::ForStmt * );
    1221                 const ast::SwitchStmt * previsit( const ast::SwitchStmt * );
    1222                 const ast::CaseStmt *   previsit( const ast::CaseStmt * );
    1223                 const ast::BranchStmt * previsit( const ast::BranchStmt * );
    1224                 const ast::ReturnStmt * previsit( const ast::ReturnStmt * );
    1225                 const ast::ThrowStmt *  previsit( const ast::ThrowStmt * );
    1226                 const ast::CatchStmt *  previsit( const ast::CatchStmt * );
    1227                 void previsit( const ast::WaitForStmt * );
    1228 
    1229                 const ast::SingleInit * previsit( const ast::SingleInit * );
    1230                 const ast::ListInit * previsit( const ast::ListInit * );
    1231                 void previsit( const ast::ConstructorInit * );
     1231                const ast::ExprStmt *        previsit( const ast::ExprStmt * );
     1232                const ast::AsmExpr *         previsit( const ast::AsmExpr * );
     1233                const ast::AsmStmt *         previsit( const ast::AsmStmt * );
     1234                const ast::IfStmt *          previsit( const ast::IfStmt * );
     1235                const ast::WhileStmt *       previsit( const ast::WhileStmt * );
     1236                const ast::ForStmt *         previsit( const ast::ForStmt * );
     1237                const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
     1238                const ast::CaseStmt *        previsit( const ast::CaseStmt * );
     1239                const ast::BranchStmt *      previsit( const ast::BranchStmt * );
     1240                const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
     1241                const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
     1242                const ast::CatchStmt *       previsit( const ast::CatchStmt * );
     1243                const ast::WaitForStmt *    previsit( const ast::WaitForStmt * );
     1244
     1245                const ast::SingleInit *      previsit( const ast::SingleInit * );
     1246                const ast::ListInit *        previsit( const ast::ListInit * );
     1247                const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
    12321248        };
    12331249
     
    13811397                                "expression." );
    13821398                       
    1383                         const ast::Expr * untyped =
     1399                        ast::ptr< ast::Expr > untyped =
    13841400                                new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
    1385                         ast::ptr< ast::Expr > newExpr = findKindExpression( untyped, symtab );
     1401                        ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, symtab );
    13861402                       
    13871403                        // case condition cannot have a cast in C, so it must be removed here, regardless of
     
    14011417                if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
    14021418                        // computed goto argument is void*
     1419                        ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
    14031420                        branchStmt = ast::mutate_field(
    14041421                                branchStmt, &ast::BranchStmt::computedTarget,
    1405                                 findSingleExpression(
    1406                                         branchStmt->computedTarget, new ast::PointerType{ new ast::VoidType{} },
    1407                                         symtab ) );
     1422                                findSingleExpression( branchStmt->computedTarget, target, symtab ) );
    14081423                }
    14091424                return branchStmt;
     
    14451460        }
    14461461
    1447         void Resolver_new::previsit( const ast::WaitForStmt * stmt ) {
    1448                 #warning unimplemented; Resolver port in progress
    1449                 (void)stmt;
    1450                 assert(false);
     1462        const ast::WaitForStmt * Resolver_new::previsit( const ast::WaitForStmt * stmt ) {
     1463                visit_children = false;
     1464
     1465                // Resolve all clauses first
     1466                for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
     1467                        const ast::WaitForStmt::Clause & clause = stmt->clauses[i];
     1468
     1469                        ast::TypeEnvironment env;
     1470                        CandidateFinder funcFinder{ symtab, env };
     1471
     1472                        // Find all candidates for a function in canonical form
     1473                        funcFinder.find( clause.target.func, ResolvMode::withAdjustment() );
     1474
     1475                        if ( funcFinder.candidates.empty() ) {
     1476                                stringstream ss;
     1477                                ss << "Use of undeclared indentifier '";
     1478                                ss << clause.target.func.strict_as< ast::NameExpr >()->name;
     1479                                ss << "' in call to waitfor";
     1480                                SemanticError( stmt->location, ss.str() );
     1481                        }
     1482
     1483                        if ( clause.target.args.empty() ) {
     1484                                SemanticError( stmt->location,
     1485                                        "Waitfor clause must have at least one mutex parameter");
     1486                        }
     1487
     1488                        // Find all alternatives for all arguments in canonical form
     1489                        std::vector< CandidateFinder > argFinders =
     1490                                funcFinder.findSubExprs( clause.target.args );
     1491                       
     1492                        // List all combinations of arguments
     1493                        std::vector< CandidateList > possibilities;
     1494                        combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
     1495
     1496                        // For every possible function:
     1497                        // * try matching the arguments to the parameters, not the other way around because
     1498                        //   more arguments than parameters
     1499                        CandidateList funcCandidates;
     1500                        std::vector< CandidateList > argsCandidates;
     1501                        SemanticErrorException errors;
     1502                        for ( CandidateRef & func : funcFinder.candidates ) {
     1503                                try {
     1504                                        auto pointerType = dynamic_cast< const ast::PointerType * >(
     1505                                                func->expr->result->stripReferences() );
     1506                                        if ( ! pointerType ) {
     1507                                                SemanticError( stmt->location, func->expr->result.get(),
     1508                                                        "candidate not viable: not a pointer type\n" );
     1509                                        }
     1510
     1511                                        auto funcType = pointerType->base.as< ast::FunctionType >();
     1512                                        if ( ! funcType ) {
     1513                                                SemanticError( stmt->location, func->expr->result.get(),
     1514                                                        "candidate not viable: not a function type\n" );
     1515                                        }
     1516
     1517                                        {
     1518                                                auto param    = funcType->params.begin();
     1519                                                auto paramEnd = funcType->params.end();
     1520
     1521                                                if( ! nextMutex( param, paramEnd ) ) {
     1522                                                        SemanticError( stmt->location, funcType,
     1523                                                                "candidate function not viable: no mutex parameters\n");
     1524                                                }
     1525                                        }
     1526
     1527                                        CandidateRef func2{ new Candidate{ *func } };
     1528                                        // strip reference from function
     1529                                        func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
     1530
     1531                                        // Each argument must be matched with a parameter of the current candidate
     1532                                        for ( auto & argsList : possibilities ) {
     1533                                                try {
     1534                                                        // Declare data structures needed for resolution
     1535                                                        ast::OpenVarSet open;
     1536                                                        ast::AssertionSet need, have;
     1537                                                        ast::TypeEnvironment resultEnv{ func->env };
     1538                                                        // Add all type variables as open so that those not used in the
     1539                                                        // parameter list are still considered open
     1540                                                        resultEnv.add( funcType->forall );
     1541
     1542                                                        // load type variables from arguments into one shared space
     1543                                                        for ( auto & arg : argsList ) {
     1544                                                                resultEnv.simpleCombine( arg->env );
     1545                                                        }
     1546
     1547                                                        // Make sure we don't widen any existing bindings
     1548                                                        resultEnv.forbidWidening();
     1549
     1550                                                        // Find any unbound type variables
     1551                                                        resultEnv.extractOpenVars( open );
     1552
     1553                                                        auto param = funcType->params.begin();
     1554                                                        auto paramEnd = funcType->params.end();
     1555
     1556                                                        unsigned n_mutex_param = 0;
     1557
     1558                                                        // For every argument of its set, check if it matches one of the
     1559                                                        // parameters. The order is important
     1560                                                        for ( auto & arg : argsList ) {
     1561                                                                // Ignore non-mutex arguments
     1562                                                                if ( ! nextMutex( param, paramEnd ) ) {
     1563                                                                        // We ran out of parameters but still have arguments.
     1564                                                                        // This function doesn't match
     1565                                                                        SemanticError( stmt->location, funcType,
     1566                                                                                toString("candidate function not viable: too many mutex "
     1567                                                                                "arguments, expected ", n_mutex_param, "\n" ) );
     1568                                                                }
     1569
     1570                                                                ++n_mutex_param;
     1571
     1572                                                                // Check if the argument matches the parameter type in the current
     1573                                                                // scope
     1574                                                                ast::ptr< ast::Type > paramType = (*param)->get_type();
     1575                                                                if (
     1576                                                                        ! unify(
     1577                                                                                arg->expr->result, paramType, resultEnv, need, have, open,
     1578                                                                                symtab )
     1579                                                                ) {
     1580                                                                        // Type doesn't match
     1581                                                                        stringstream ss;
     1582                                                                        ss << "candidate function not viable: no known conversion "
     1583                                                                                "from '";
     1584                                                                        ast::print( ss, (*param)->get_type() );
     1585                                                                        ss << "' to '";
     1586                                                                        ast::print( ss, arg->expr->result );
     1587                                                                        ss << "' with env '";
     1588                                                                        ast::print( ss, resultEnv );
     1589                                                                        ss << "'\n";
     1590                                                                        SemanticError( stmt->location, funcType, ss.str() );
     1591                                                                }
     1592
     1593                                                                ++param;
     1594                                                        }
     1595
     1596                                                        // All arguments match!
     1597
     1598                                                        // Check if parameters are missing
     1599                                                        if ( nextMutex( param, paramEnd ) ) {
     1600                                                                do {
     1601                                                                        ++n_mutex_param;
     1602                                                                        ++param;
     1603                                                                } while ( nextMutex( param, paramEnd ) );
     1604
     1605                                                                // We ran out of arguments but still have parameters left; this
     1606                                                                // function doesn't match
     1607                                                                SemanticError( stmt->location, funcType,
     1608                                                                        toString( "candidate function not viable: too few mutex "
     1609                                                                        "arguments, expected ", n_mutex_param, "\n" ) );
     1610                                                        }
     1611
     1612                                                        // All parameters match!
     1613
     1614                                                        // Finish the expressions to tie in proper environments
     1615                                                        finishExpr( func2->expr, resultEnv );
     1616                                                        for ( CandidateRef & arg : argsList ) {
     1617                                                                finishExpr( arg->expr, resultEnv );
     1618                                                        }
     1619
     1620                                                        // This is a match, store it and save it for later
     1621                                                        funcCandidates.emplace_back( std::move( func2 ) );
     1622                                                        argsCandidates.emplace_back( std::move( argsList ) );
     1623
     1624                                                } catch ( SemanticErrorException & e ) {
     1625                                                        errors.append( e );
     1626                                                }
     1627                                        }
     1628                                } catch ( SemanticErrorException & e ) {
     1629                                        errors.append( e );
     1630                                }
     1631                        }
     1632
     1633                        // Make sure correct number of arguments
     1634                        if( funcCandidates.empty() ) {
     1635                                SemanticErrorException top( stmt->location,
     1636                                        "No alternatives for function in call to waitfor" );
     1637                                top.append( errors );
     1638                                throw top;
     1639                        }
     1640
     1641                        if( argsCandidates.empty() ) {
     1642                                SemanticErrorException top( stmt->location,
     1643                                        "No alternatives for arguments in call to waitfor" );
     1644                                top.append( errors );
     1645                                throw top;
     1646                        }
     1647
     1648                        if( funcCandidates.size() > 1 ) {
     1649                                SemanticErrorException top( stmt->location,
     1650                                        "Ambiguous function in call to waitfor" );
     1651                                top.append( errors );
     1652                                throw top;
     1653                        }
     1654                        if( argsCandidates.size() > 1 ) {
     1655                                SemanticErrorException top( stmt->location,
     1656                                        "Ambiguous arguments in call to waitfor" );
     1657                                top.append( errors );
     1658                                throw top;
     1659                        }
     1660                        // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
     1661
     1662                        // build new clause
     1663                        ast::WaitForStmt::Clause clause2;
     1664                       
     1665                        clause2.target.func = funcCandidates.front()->expr;
     1666                       
     1667                        clause2.target.args.reserve( clause.target.args.size() );
     1668                        for ( auto arg : argsCandidates.front() ) {
     1669                                clause2.target.args.emplace_back( std::move( arg->expr ) );
     1670                        }
     1671
     1672                        // Resolve the conditions as if it were an IfStmt, statements normally
     1673                        clause2.cond = findSingleExpression( clause.cond, symtab );
     1674                        clause2.stmt = clause.stmt->accept( *visitor );
     1675
     1676                        // set results into stmt
     1677                        auto n = mutate( stmt );
     1678                        n->clauses[i] = std::move( clause2 );
     1679                        stmt = n;
     1680                }
     1681
     1682                if ( stmt->timeout.stmt ) {
     1683                        // resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
     1684                        ast::WaitForStmt::Timeout timeout2;
     1685
     1686                        ast::ptr< ast::Type > target =
     1687                                new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
     1688                        timeout2.time = findSingleExpression( stmt->timeout.time, target, symtab );
     1689                        timeout2.cond = findSingleExpression( stmt->timeout.cond, symtab );
     1690                        timeout2.stmt = stmt->timeout.stmt->accept( *visitor );
     1691
     1692                        // set results into stmt
     1693                        auto n = mutate( stmt );
     1694                        n->timeout = std::move( timeout2 );
     1695                        stmt = n;
     1696                }
     1697
     1698                if ( stmt->orElse.stmt ) {
     1699                        // resolve the condition like IfStmt, stmts normally
     1700                        ast::WaitForStmt::OrElse orElse2;
     1701
     1702                        orElse2.cond = findSingleExpression( stmt->orElse.cond, symtab );
     1703                        orElse2.stmt = stmt->orElse.stmt->accept( *visitor );
     1704
     1705                        // set results into stmt
     1706                        auto n = mutate( stmt );
     1707                        n->orElse = std::move( orElse2 );
     1708                        stmt = n;
     1709                }
     1710
     1711                return stmt;
    14511712        }
    14521713
     
    14571718                // resolve initialization using the possibilities as determined by the `currentObject`
    14581719                // cursor.
    1459                 ast::Expr * untyped = new ast::UntypedInitExpr{
     1720                ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
    14601721                        singleInit->location, singleInit->value, currentObject.getOptions() };
    1461                 ast::ptr<ast::Expr> newExpr = findKindExpression( untyped, symtab );
     1722                ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, symtab );
    14621723                const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
    14631724
     
    15101771                        // iterate designations and initializers in pairs, moving the cursor to the current
    15111772                        // designated object and resolving the initializer against that object
    1512                         #warning unimplemented; Resolver port in progress
    1513                         assert(false);
    1514                 }
     1773                        listInit = ast::mutate_field_index(
     1774                                listInit, &ast::ListInit::designations, i,
     1775                                currentObject.findNext( listInit->designations[i] ) );
     1776                        listInit = ast::mutate_field_index(
     1777                                listInit, &ast::ListInit::initializers, i,
     1778                                listInit->initializers[i]->accept( *visitor ) );
     1779                }
     1780
     1781                // move cursor out of brace-enclosed initializer-list
     1782                currentObject.exitListInit();
    15151783
    15161784                visit_children = false;
     
    15181786        }
    15191787
    1520         void Resolver_new::previsit( const ast::ConstructorInit * ctorInit ) {
    1521                 #warning unimplemented; Resolver port in progress
    1522                 (void)ctorInit;
    1523                 assert(false);
     1788        const ast::ConstructorInit * Resolver_new::previsit( const ast::ConstructorInit * ctorInit ) {
     1789                visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
     1790                visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
     1791
     1792                // found a constructor - can get rid of C-style initializer
     1793                // xxx - Rob suggests this field is dead code
     1794                ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
     1795
     1796                // intrinsic single-parameter constructors and destructors do nothing. Since this was
     1797                // implicitly generated, there's no way for it to have side effects, so get rid of it to
     1798                // clean up generated code
     1799                if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
     1800                        ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
     1801                }
     1802                if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
     1803                        ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
     1804                }
     1805
     1806                return ctorInit;
    15241807        }
    15251808
  • src/ResolvExpr/Resolver.h

    raaeacf4 r21300d7  
    1717
    1818#include <list>          // for list
    19 #include <AST/Node.hpp>  // for ptr
     19
     20#include "AST/Node.hpp"  // for ptr
    2021
    2122class ConstructorInit;
     
    2930namespace ast {
    3031        class Decl;
     32        class DeletedExpr;
     33        class SymbolTable;
     34        class TypeEnvironment;
    3135} // namespace ast
    3236
     
    4852        /// Checks types and binds syntactic constructs to typed representations
    4953        void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );
     54        /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
     55        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
     56        /// Find the expression candidate that is the unique best match for `untyped` in a `void`
     57        /// context.
     58        ast::ptr< ast::Expr > resolveInVoidContext(
     59                const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env );
    5060} // namespace ResolvExpr
    5161
  • src/ResolvExpr/Unify.cc

    raaeacf4 r21300d7  
    11431143                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    11441144                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     1145                        ast::OpenVarSet & open, const ast::SymbolTable & symtab
     1146        ) {
     1147                ast::ptr<ast::Type> common;
     1148                return unify( type1, type2, env, need, have, open, symtab, common );
     1149        }
     1150
     1151        bool unify(
     1152                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     1153                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    11451154                        ast::OpenVarSet & open, const ast::SymbolTable & symtab, ast::ptr<ast::Type> & common
    11461155        ) {
  • src/ResolvExpr/Unify.h

    raaeacf4 r21300d7  
    7272                const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    7373                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     74                ast::OpenVarSet & open, const ast::SymbolTable & symtab );
     75
     76        bool unify(
     77                const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     78                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    7479                ast::OpenVarSet & open, const ast::SymbolTable & symtab, ast::ptr<ast::Type> & common );
    7580
  • src/ResolvExpr/module.mk

    raaeacf4 r21300d7  
    2626      ResolvExpr/CurrentObject.cc \
    2727      ResolvExpr/ExplodedActual.cc \
     28      ResolvExpr/ExplodedArg.cpp \
    2829      ResolvExpr/FindOpenVars.cc \
    2930      ResolvExpr/Occurs.cc \
     
    3536      ResolvExpr/Resolver.cc \
    3637      ResolvExpr/ResolveTypeof.cc \
     38      ResolvExpr/SatisfyAssertions.cpp \
    3739      ResolvExpr/SpecCost.cc \
    3840      ResolvExpr/TypeEnvironment.cc \
  • src/ResolvExpr/typeops.h

    raaeacf4 r21300d7  
    7171                } // while
    7272        }
     73
     74        /// Replaces array types with equivalent pointer, and function types with a pointer-to-function
     75        const ast::Type * adjustExprType(
     76                const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab );
    7377
    7478        // in CastCost.cc
  • src/Tuples/Explode.h

    raaeacf4 r21300d7  
    1919#include <utility>                      // for forward
    2020
     21#include "AST/Expr.hpp"
    2122#include "ResolvExpr/Alternative.h"     // for Alternative, AltList
     23#include "ResolvExpr/Candidate.hpp"     // for Candidate, CandidateList
    2224#include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
     25#include "ResolvExpr/ExplodedArg.hpp"   // for ExplodedArg
    2326#include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
    2427#include "SynTree/Type.h"               // for TupleType, Type
    2528#include "Tuples.h"                     // for maybeImpure
     29
     30namespace ast {
     31        class SymbolTable;
     32}
    2633
    2734namespace SymTab {
     
    130137                explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );
    131138        }
     139
     140/// helper function used by explode
     141template< typename Output >
     142void explodeUnique(
     143        const ast::Expr * expr, const ResolvExpr::Candidate & arg, const ast::SymbolTable & symtab,
     144        Output && out, bool isTupleAssign
     145) {
     146        #warning unimplemented
     147        (void)expr; (void)arg; (void)symtab; (void)out; (void)isTupleAssign;
     148        assert(false);
     149}
     150
     151/// expands a tuple-valued candidate into multiple candidates, each with a non-tuple type
     152template< typename Output >
     153void explode(
     154        const ResolvExpr::Candidate & arg, const ast::SymbolTable & symtab, Output && out,
     155        bool isTupleAssign = false
     156) {
     157        explodeUnique( arg.expr, arg, symtab, std::forward< Output >( out ), isTupleAssign );
     158}
     159
    132160} // namespace Tuples
    133161
  • src/Tuples/TupleAssignment.cc

    raaeacf4 r21300d7  
    377377                }
    378378        }
     379
     380        void handleTupleAssignment(
     381                ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     382                std::vector< ResolvExpr::CandidateFinder > & args
     383        ) {
     384                #warning unimplmented
     385                (void)finder; (void)assign; (void)args;
     386                assert(false);
     387        }
    379388} // namespace Tuples
    380389
  • src/Tuples/Tuples.h

    raaeacf4 r21300d7  
    2626
    2727#include "ResolvExpr/AlternativeFinder.h"
     28#include "ResolvExpr/CandidateFinder.hpp"
    2829
    2930namespace Tuples {
     
    3132        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
    3233                std::vector< ResolvExpr::AlternativeFinder >& args );
     34        void handleTupleAssignment(
     35                ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     36                std::vector< ResolvExpr::CandidateFinder > & args );
    3337
    3438        // TupleExpansion.cc
  • tests/sum.cfa

    raaeacf4 r21300d7  
    1111// Created On       : Wed May 27 17:56:53 2015
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Sun May 19 11:21:02 2019
    14 // Update Count     : 330
     13// Last Modified On : Thu Jun  6 16:18:22 2019
     14// Update Count     : 333
    1515//
    1616
     
    111111        };
    112112        GS(int) gs;
    113         gs.x = anew( size );                                                            // create array storage for field
     113        // FIX ME, resolution problem with anew not picking up the LH type
     114        gs.x = (typeof(gs.x))anew( size );                                      // create array storage for field
    114115        s = 0; v = low;
    115116        for ( int i = 0; i < size; i += 1, v += 1 ) {
Note: See TracChangeset for help on using the changeset viewer.