Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/SymTab/Validate.cc

    r44547b0 r5408b59  
    4747#include <utility>                     // for pair
    4848
     49#include "AST/Chain.hpp"
     50#include "AST/Decl.hpp"
     51#include "AST/Node.hpp"
     52#include "AST/Pass.hpp"
     53#include "AST/SymbolTable.hpp"
     54#include "AST/Type.hpp"
     55#include "AST/TypeSubstitution.hpp"
    4956#include "CodeGen/CodeGenerator.h"     // for genName
    5057#include "CodeGen/OperatorTable.h"     // for isCtorDtor, isCtorDtorAssign
     
    13191326        }
    13201327
     1328namespace {
     1329        /// Replaces enum types by int, and function/array types in function parameter and return
     1330        /// lists by appropriate pointers
     1331        /*
     1332        struct EnumAndPointerDecay_new {
     1333                const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) {
     1334                        // set the type of each member of the enumeration to be EnumConstant
     1335                        for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {
     1336                                // build new version of object with EnumConstant
     1337                                ast::ptr< ast::ObjectDecl > obj =
     1338                                        enumDecl->members[i].strict_as< ast::ObjectDecl >();
     1339                                obj.get_and_mutate()->type =
     1340                                        new ast::EnumInstType{ enumDecl->name, ast::CV::Const };
     1341
     1342                                // set into decl
     1343                                ast::EnumDecl * mut = mutate( enumDecl );
     1344                                mut->members[i] = obj.get();
     1345                                enumDecl = mut;
     1346                        }
     1347                        return enumDecl;
     1348                }
     1349
     1350                static const ast::FunctionType * fixFunctionList(
     1351                        const ast::FunctionType * func,
     1352                        std::vector< ast::ptr< ast::DeclWithType > > ast::FunctionType::* field,
     1353                        ast::ArgumentFlag isVarArgs = ast::FixedArgs
     1354                ) {
     1355                        const auto & dwts = func->* field;
     1356                        unsigned nvals = dwts.size();
     1357                        bool hasVoid = false;
     1358                        for ( unsigned i = 0; i < nvals; ++i ) {
     1359                                func = ast::mutate_field_index( func, field, i, fixFunction( dwts[i], hasVoid ) );
     1360                        }
     1361
     1362                        // the only case in which "void" is valid is where it is the only one in the list
     1363                        if ( hasVoid && ( nvals > 1 || isVarArgs ) ) {
     1364                                SemanticError(
     1365                                        dwts.front()->location, func, "invalid type void in function type" );
     1366                        }
     1367
     1368                        // one void is the only thing in the list, remove it
     1369                        if ( hasVoid ) {
     1370                                func = ast::mutate_field(
     1371                                        func, field, std::vector< ast::ptr< ast::DeclWithType > >{} );
     1372                        }
     1373
     1374                        return func;
     1375                }
     1376
     1377                const ast::FunctionType * previsit( const ast::FunctionType * func ) {
     1378                        func = fixFunctionList( func, &ast::FunctionType::params, func->isVarArgs );
     1379                        return fixFunctionList( func, &ast::FunctionType::returns );
     1380                }
     1381        };
     1382
     1383        /// expand assertions from a trait instance, performing appropriate type variable substitutions
     1384        void expandAssertions(
     1385                const ast::TraitInstType * inst, std::vector< ast::ptr< ast::DeclWithType > > & out
     1386        ) {
     1387                assertf( inst->base, "Trait instance not linked to base trait: %s", toCString( inst ) );
     1388
     1389                // build list of trait members, substituting trait decl parameters for instance parameters
     1390                ast::TypeSubstitution sub{
     1391                        inst->base->params.begin(), inst->base->params.end(), inst->params.begin() };
     1392                // deliberately take ast::ptr by-value to ensure this does not mutate inst->base
     1393                for ( ast::ptr< ast::Decl > decl : inst->base->members ) {
     1394                        auto member = decl.strict_as< ast::DeclWithType >();
     1395                        sub.apply( member );
     1396                        out.emplace_back( member );
     1397                }
     1398        }
     1399
     1400        /// Associates forward declarations of aggregates with their definitions
     1401        class LinkReferenceToTypes_new final
     1402        : public ast::WithSymbolTable, public ast::WithGuards, public
     1403          ast::WithVisitorRef<LinkReferenceToTypes_new>, public ast::WithShortCircuiting {
     1404
     1405                // these maps of uses of forward declarations of types need to have the actual type
     1406                // declaration switched in * after * they have been traversed. To enable this in the
     1407                // ast::Pass framework, any node that needs to be so mutated has mutate() called on it
     1408                // before it is placed in the map, properly updating its parents in the usual traversal,
     1409                // then can have the actual mutation applied later
     1410                using ForwardEnumsType = std::unordered_multimap< std::string, ast::EnumInstType * >;
     1411                using ForwardStructsType = std::unordered_multimap< std::string, ast::StructInstType * >;
     1412                using ForwardUnionsType = std::unordered_multimap< std::string, ast::UnionInstType * >;
     1413
     1414                const CodeLocation & location;
     1415                const ast::SymbolTable * localSymtab;
     1416
     1417                ForwardEnumsType forwardEnums;
     1418                ForwardStructsType forwardStructs;
     1419                ForwardUnionsType forwardUnions;
     1420
     1421                /// true if currently in a generic type body, so that type parameter instances can be
     1422                /// renamed appropriately
     1423                bool inGeneric = false;
     1424
     1425        public:
     1426                /// contstruct using running symbol table
     1427                LinkReferenceToTypes_new( const CodeLocation & loc )
     1428                : location( loc ), localSymtab( &symtab ) {}
     1429
     1430                /// construct using provided symbol table
     1431                LinkReferenceToTypes_new( const CodeLocation & loc, const ast::SymbolTable & syms )
     1432                : location( loc ), localSymtab( &syms ) {}
     1433
     1434                const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
     1435                        // ensure generic parameter instances are renamed like the base type
     1436                        if ( inGeneric && typeInst->base ) {
     1437                                typeInst = ast::mutate_field(
     1438                                        typeInst, &ast::TypeInstType::name, typeInst->base->name );
     1439                        }
     1440
     1441                        if (
     1442                                auto typeDecl = dynamic_cast< const ast::TypeDecl * >(
     1443                                        localSymtab->lookupType( typeInst->name ) )
     1444                        ) {
     1445                                typeInst = ast::mutate_field( typeInst, &ast::TypeInstType::kind, typeDecl->kind );
     1446                        }
     1447
     1448                        return typeInst;
     1449                }
     1450
     1451                const ast::Type * postvisit( const ast::EnumInstType * inst ) {
     1452                        const ast::EnumDecl * decl = localSymtab->lookupEnum( inst->name );
     1453                        // not a semantic error if the enum is not found, just an implicit forward declaration
     1454                        if ( decl ) {
     1455                                inst = ast::mutate_field( inst, &ast::EnumInstType::base, decl );
     1456                        }
     1457                        if ( ! decl || ! decl->body ) {
     1458                                // forward declaration
     1459                                auto mut = mutate( inst );
     1460                                forwardEnums.emplace( inst->name, mut );
     1461                                inst = mut;
     1462                        }
     1463                        return inst;
     1464                }
     1465
     1466                void checkGenericParameters( const ast::BaseInstType * inst ) {
     1467                        for ( const ast::Expr * param : inst->params ) {
     1468                                if ( ! dynamic_cast< const ast::TypeExpr * >( param ) ) {
     1469                                        SemanticError(
     1470                                                location, inst, "Expression parameters for generic types are currently "
     1471                                                "unsupported: " );
     1472                                }
     1473                        }
     1474                }
     1475
     1476                const ast::StructInstType * postvisit( const ast::StructInstType * inst ) {
     1477                        const ast::StructDecl * decl = localSymtab->lookupStruct( inst->name );
     1478                        // not a semantic error if the struct is not found, just an implicit forward declaration
     1479                        if ( decl ) {
     1480                                inst = ast::mutate_field( inst, &ast::StructInstType::base, decl );
     1481                        }
     1482                        if ( ! decl || ! decl->body ) {
     1483                                // forward declaration
     1484                                auto mut = mutate( inst );
     1485                                forwardStructs.emplace( inst->name, mut );
     1486                                inst = mut;
     1487                        }
     1488                        checkGenericParameters( inst );
     1489                        return inst;
     1490                }
     1491
     1492                const ast::UnionInstType * postvisit( const ast::UnionInstType * inst ) {
     1493                        const ast::UnionDecl * decl = localSymtab->lookupUnion( inst->name );
     1494                        // not a semantic error if the struct is not found, just an implicit forward declaration
     1495                        if ( decl ) {
     1496                                inst = ast::mutate_field( inst, &ast::UnionInstType::base, decl );
     1497                        }
     1498                        if ( ! decl || ! decl->body ) {
     1499                                // forward declaration
     1500                                auto mut = mutate( inst );
     1501                                forwardUnions.emplace( inst->name, mut );
     1502                                inst = mut;
     1503                        }
     1504                        checkGenericParameters( inst );
     1505                        return inst;
     1506                }
     1507
     1508                const ast::Type * postvisit( const ast::TraitInstType * traitInst ) {
     1509                        // handle other traits
     1510                        const ast::TraitDecl * traitDecl = localSymtab->lookupTrait( traitInst->name );
     1511                        if ( ! traitDecl )       {
     1512                                SemanticError( location, "use of undeclared trait " + traitInst->name );
     1513                        }
     1514                        if ( traitDecl->params.size() != traitInst->params.size() ) {
     1515                                SemanticError( location, traitInst, "incorrect number of trait parameters: " );
     1516                        }
     1517                        traitInst = ast::mutate_field( traitInst, &ast::TraitInstType::base, traitDecl );
     1518
     1519                        // need to carry over the "sized" status of each decl in the instance
     1520                        for ( unsigned i = 0; i < traitDecl->params.size(); ++i ) {
     1521                                auto expr = traitInst->params[i].as< ast::TypeExpr >();
     1522                                if ( ! expr ) {
     1523                                        SemanticError(
     1524                                                traitInst->params[i].get(), "Expression parameters for trait instances "
     1525                                                "are currently unsupported: " );
     1526                                }
     1527
     1528                                if ( auto inst = expr->type.as< ast::TypeInstType >() ) {
     1529                                        if ( traitDecl->params[i]->sized && ! inst->base->sized ) {
     1530                                                // traitInst = ast::mutate_field_index(
     1531                                                //      traitInst, &ast::TraitInstType::params, i,
     1532                                                //      ...
     1533                                                // );
     1534                                                ast::TraitInstType * mut = ast::mutate( traitInst );
     1535                                                ast::chain_mutate( mut->params[i] )
     1536                                                        ( &ast::TypeExpr::type )
     1537                                                                ( &ast::TypeInstType::base )->sized = true;
     1538                                                traitInst = mut;
     1539                                        }
     1540                                }
     1541                        }
     1542
     1543                        return traitInst;
     1544                }
     1545
     1546                void previsit( const ast::QualifiedType * ) { visit_children = false; }
     1547
     1548                const ast::Type * postvisit( const ast::QualifiedType * qualType ) {
     1549                        // linking only makes sense for the "oldest ancestor" of the qualified type
     1550                        return ast::mutate_field(
     1551                                qualType, &ast::QualifiedType::parent, qualType->parent->accept( * visitor ) );
     1552                }
     1553
     1554                const ast::Decl * postvisit( const ast::EnumDecl * enumDecl ) {
     1555                        // visit enum members first so that the types of self-referencing members are updated
     1556                        // properly
     1557                        if ( ! enumDecl->body ) return enumDecl;
     1558
     1559                        // update forward declarations to point here
     1560                        auto fwds = forwardEnums.equal_range( enumDecl->name );
     1561                        if ( fwds.first != fwds.second ) {
     1562                                auto inst = fwds.first;
     1563                                do {
     1564                                        // forward decl is stored * mutably * in map, can thus be updated
     1565                                        inst->second->base = enumDecl;
     1566                                } while ( ++inst != fwds.second );
     1567                                forwardEnums.erase( fwds.first, fwds.second );
     1568                        }
     1569
     1570                        // ensure that enumerator initializers are properly set
     1571                        for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {
     1572                                auto field = enumDecl->members[i].strict_as< ast::ObjectDecl >();
     1573                                if ( field->init ) {
     1574                                        // need to resolve enumerator initializers early so that other passes that
     1575                                        // determine if an expression is constexpr have appropriate information
     1576                                        auto init = field->init.strict_as< ast::SingleInit >();
     1577
     1578                                        enumDecl = ast::mutate_field_index(
     1579                                                enumDecl, &ast::EnumDecl::members, i,
     1580                                                ast::mutate_field( field, &ast::ObjectDecl::init,
     1581                                                        ast::mutate_field( init, &ast::SingleInit::value,
     1582                                                                ResolvExpr::findSingleExpression(
     1583                                                                        init->value, new ast::BasicType{ ast::BasicType::SignedInt },
     1584                                                                        symtab ) ) ) );
     1585                                }
     1586                        }
     1587
     1588                        return enumDecl;
     1589                }
     1590
     1591                /// rename generic type parameters uniquely so that they do not conflict with user defined
     1592                /// function forall parameters, e.g. the T in Box and the T in f, below
     1593                ///   forall(otype T)
     1594                ///   struct Box {
     1595                ///     T x;
     1596                ///   };
     1597                ///   forall(otype T)
     1598                ///   void f(Box(T) b) {
     1599                ///     ...
     1600                ///   }
     1601                template< typename AggrDecl >
     1602                const AggrDecl * renameGenericParams( const AggrDecl * aggr ) {
     1603                        GuardValue( inGeneric );
     1604                        inGeneric = ! aggr->params.empty();
     1605
     1606                        for ( unsigned i = 0; i < aggr->params.size(); ++i ) {
     1607                                const ast::TypeDecl * td = aggr->params[i];
     1608
     1609                                aggr = ast::mutate_field_index(
     1610                                        aggr, &AggrDecl::params, i,
     1611                                        ast::mutate_field( td, &ast::TypeDecl::name, "__" + td->name + "_generic_" ) );
     1612                        }
     1613                        return aggr;
     1614                }
     1615
     1616                const ast::StructDecl * previsit( const ast::StructDecl * structDecl ) {
     1617                        return renameGenericParams( structDecl );
     1618                }
     1619
     1620                void postvisit( const ast::StructDecl * structDecl ) {
     1621                        // visit struct members first so that the types of self-referencing members are
     1622                        // updated properly
     1623                        if ( ! structDecl->body ) return;
     1624
     1625                        // update forward declarations to point here
     1626                        auto fwds = forwardStructs.equal_range( structDecl->name );
     1627                        if ( fwds.first != fwds.second ) {
     1628                                auto inst = fwds.first;
     1629                                do {
     1630                                        // forward decl is stored * mutably * in map, can thus be updated
     1631                                        inst->second->base = structDecl;
     1632                                } while ( ++inst != fwds.second );
     1633                                forwardStructs.erase( fwds.first, fwds.second );
     1634                        }
     1635                }
     1636
     1637                const ast::UnionDecl * previsit( const ast::UnionDecl * unionDecl ) {
     1638                        return renameGenericParams( unionDecl );
     1639                }
     1640
     1641                void postvisit( const ast::UnionDecl * unionDecl ) {
     1642                        // visit union members first so that the types of self-referencing members are updated
     1643                        // properly
     1644                        if ( ! unionDecl->body ) return;
     1645
     1646                        // update forward declarations to point here
     1647                        auto fwds = forwardUnions.equal_range( unionDecl->name );
     1648                        if ( fwds.first != fwds.second ) {
     1649                                auto inst = fwds.first;
     1650                                do {
     1651                                        // forward decl is stored * mutably * in map, can thus be updated
     1652                                        inst->second->base = unionDecl;
     1653                                } while ( ++inst != fwds.second );
     1654                                forwardUnions.erase( fwds.first, fwds.second );
     1655                        }
     1656                }
     1657
     1658                const ast::Decl * postvisit( const ast::TraitDecl * traitDecl ) {
     1659                        // set the "sized" status for the special "sized" trait
     1660                        if ( traitDecl->name == "sized" ) {
     1661                                assertf( traitDecl->params.size() == 1, "Built-in trait 'sized' has incorrect "
     1662                                        "number of parameters: %zd", traitDecl->params.size() );
     1663
     1664                                traitDecl = ast::mutate_field_index(
     1665                                        traitDecl, &ast::TraitDecl::params, 0,
     1666                                        ast::mutate_field(
     1667                                                traitDecl->params.front().get(), &ast::TypeDecl::sized, true ) );
     1668                        }
     1669
     1670                        // move assertions from type parameters into the body of the trait
     1671                        std::vector< ast::ptr< ast::DeclWithType > > added;
     1672                        for ( const ast::TypeDecl * td : traitDecl->params ) {
     1673                                for ( const ast::DeclWithType * assn : td->assertions ) {
     1674                                        auto inst = dynamic_cast< const ast::TraitInstType * >( assn->get_type() );
     1675                                        if ( inst ) {
     1676                                                expandAssertions( inst, added );
     1677                                        } else {
     1678                                                added.emplace_back( assn );
     1679                                        }
     1680                                }
     1681                        }
     1682                        if ( ! added.empty() ) {
     1683                                auto mut = mutate( traitDecl );
     1684                                for ( const ast::DeclWithType * decl : added ) {
     1685                                        mut->members.emplace_back( decl );
     1686                                }
     1687                                traitDecl = mut;
     1688                        }
     1689
     1690                        return traitDecl;
     1691                }
     1692        };
     1693
     1694        /// Replaces array and function types in forall lists by appropriate pointer type and assigns
     1695        /// each object and function declaration a unique ID
     1696        class ForallPointerDecay_new {
     1697                const CodeLocation & location;
     1698        public:
     1699                ForallPointerDecay_new( const CodeLocation & loc ) : location( loc ) {}
     1700
     1701                const ast::ObjectDecl * previsit( const ast::ObjectDecl * obj ) {
     1702                        // ensure that operator names only apply to functions or function pointers
     1703                        if (
     1704                                CodeGen::isOperator( obj->name )
     1705                                && ! dynamic_cast< const ast::FunctionType * >( obj->type->stripDeclarator() )
     1706                        ) {
     1707                                SemanticError( obj->location, toCString( "operator ", obj->name.c_str(), " is not "
     1708                                        "a function or function pointer." )  );
     1709                        }
     1710
     1711                        // ensure object has unique ID
     1712                        if ( obj->uniqueId ) return obj;
     1713                        auto mut = mutate( obj );
     1714                        mut->fixUniqueId();
     1715                        return mut;
     1716                }
     1717
     1718                const ast::FunctionDecl * previsit( const ast::FunctionDecl * func ) {
     1719                        // ensure function has unique ID
     1720                        if ( func->uniqueId ) return func;
     1721                        auto mut = mutate( func );
     1722                        mut->fixUniqueId();
     1723                        return mut;
     1724                }
     1725
     1726                /// Fix up assertions -- flattens assertion lists, removing all trait instances
     1727                template< typename node_t, typename parent_t >
     1728                static const node_t * forallFixer(
     1729                        const CodeLocation & loc, const node_t * node,
     1730                        ast::FunctionType::ForallList parent_t::* forallField
     1731                ) {
     1732                        for ( unsigned i = 0; i < (node->* forallField).size(); ++i ) {
     1733                                const ast::TypeDecl * type = (node->* forallField)[i];
     1734                                if ( type->assertions.empty() ) continue;
     1735
     1736                                std::vector< ast::ptr< ast::DeclWithType > > asserts;
     1737                                asserts.reserve( type->assertions.size() );
     1738
     1739                                // expand trait instances into their members
     1740                                for ( const ast::DeclWithType * assn : type->assertions ) {
     1741                                        auto traitInst =
     1742                                                dynamic_cast< const ast::TraitInstType * >( assn->get_type() );
     1743                                        if ( traitInst ) {
     1744                                                // expand trait instance to all its members
     1745                                                expandAssertions( traitInst, asserts );
     1746                                        } else {
     1747                                                // pass other assertions through
     1748                                                asserts.emplace_back( assn );
     1749                                        }
     1750                                }
     1751
     1752                                // apply FixFunction to every assertion to check for invalid void type
     1753                                for ( ast::ptr< ast::DeclWithType > & assn : asserts ) {
     1754                                        bool isVoid = false;
     1755                                        assn = fixFunction( assn, isVoid );
     1756                                        if ( isVoid ) {
     1757                                                SemanticError( loc, node, "invalid type void in assertion of function " );
     1758                                        }
     1759                                }
     1760
     1761                                // place mutated assertion list in node
     1762                                auto mut = mutate( type );
     1763                                mut->assertions = move( asserts );
     1764                                node = ast::mutate_field_index( node, forallField, i, mut );
     1765                        }
     1766                        return node;
     1767                }
     1768
     1769                const ast::FunctionType * previsit( const ast::FunctionType * ftype ) {
     1770                        return forallFixer( location, ftype, &ast::FunctionType::forall );
     1771                }
     1772
     1773                const ast::StructDecl * previsit( const ast::StructDecl * aggrDecl ) {
     1774                        return forallFixer( aggrDecl->location, aggrDecl, &ast::StructDecl::params );
     1775                }
     1776
     1777                const ast::UnionDecl * previsit( const ast::UnionDecl * aggrDecl ) {
     1778                        return forallFixer( aggrDecl->location, aggrDecl, &ast::UnionDecl::params );
     1779                }
     1780        };
     1781        */
     1782} // anonymous namespace
     1783
     1784/*
     1785const ast::Type * validateType(
     1786                const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) {
     1787        // ast::Pass< EnumAndPointerDecay_new > epc;
     1788        ast::Pass< LinkReferenceToTypes_new > lrt{ loc, symtab };
     1789        ast::Pass< ForallPointerDecay_new > fpd{ loc };
     1790
     1791        return type->accept( lrt )->accept( fpd );
     1792}
     1793*/
     1794
    13211795} // namespace SymTab
    13221796
Note: See TracChangeset for help on using the changeset viewer.