source: src/GenPoly/InstantiateGenericNew.cpp @ db6cdc0

ADTast-experimental
Last change on this file since db6cdc0 was 1dafdfc, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Moved code from _dtype_static_member_ initializer to an assignment in a comma expression. Fixes bug #266, added a test.

  • Property mode set to 100644
File size: 23.9 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 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// InstantiateGenericNew.cpp --
8//
9// Author           : Andrew Beach
10// Created On       : Tue Aug 16 10:51:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Oct 31 16:48:00 2022
13// Update Count     : 1
14//
15
16#include "InstantiateGeneric.h"
17
18#include <cassert>                     // for assertf, assert
19#include <set>                         // for set
20#include <utility>                     // for move, pair
21#include <vector>                      // for vector
22
23#include "AST/Copy.hpp"                // for deepCopy
24#include "AST/Create.hpp"              // for asForward
25#include "AST/Inspect.hpp"             // for getFunction
26#include "AST/Pass.hpp"                // for Pass, WithGuard, WithShortCi...
27#include "AST/TranslationUnit.hpp"     // for TranslationUnit
28#include "AST/Vector.hpp"              // for vector
29#include "CodeGen/OperatorTable.h"     // for isAssignment
30#include "Common/ScopedMap.h"          // for ScopedMap
31#include "Common/UniqueName.h"         // for UniqueName
32#include "GenPoly/GenPoly.h"           // for isPolyType, typesPolyCompatible
33#include "GenPoly/ScrubTyVars.h"       // for scrubAll
34#include "ResolvExpr/typeops.h"        // for typesCompatible
35
36namespace GenPoly {
37
38namespace {
39
40// Utilities:
41
42using type_vector = ast::vector< ast::TypeExpr >;
43
44/// Abstracts type equality for a list of parameter types.
45struct TypeList {
46        TypeList() : params() {}
47        TypeList( ast::vector< ast::Type > const & params ) :
48                params( params ) {}
49        TypeList( ast::vector< ast::Type > && params ) :
50                params( std::move( params ) ) {}
51        TypeList( TypeList const & that ) : params( that.params ) {}
52        TypeList( TypeList && that ) : params( std::move( that.params ) ) {}
53
54        TypeList( ast::vector< ast::TypeExpr > const & exprs ) :
55                        params() {
56                for ( auto expr : exprs ) {
57                        params.emplace_back( ast::deepCopy( expr->type ) );
58                }
59        }
60
61        TypeList & operator=( TypeList const & that ) {
62                params = that.params;
63                return *this;
64        }
65
66        TypeList & operator=( TypeList && that ) {
67                params = std::move( that.params );
68                return *this;
69        }
70
71        bool operator==( TypeList const & that ) const {
72                if ( params.size() != that.params.size() ) {
73                        return false;
74                }
75
76                for ( auto it = params.begin(), jt = that.params.begin() ;
77                                it != params.end() ; ++it, ++jt ) {
78                        if ( !typesPolyCompatible( it->get(), jt->get() ) ) {
79                                return false;
80                        }
81                }
82                return true;
83        }
84
85        ast::vector<ast::Type> params;
86};
87
88/// Maps a key and a TypeList to a valuue. Also supports scoping.
89class InstantiationMap final {
90        /// Wraps value for a specific (AggregateDecl, TypeList) combination.
91        using Instantiation = std::pair<TypeList, ast::ptr<ast::AggregateDecl>>;
92        /// List of TypeLists paired with the appropriate values.
93        using ValueList = std::vector<Instantiation>;
94        /// Underlying map type; maps keys to a linear list of corresponding
95        /// TypeLists and values.
96        using InnerMap = ScopedMap<ast::ptr<ast::AggregateDecl>, ValueList>;
97
98        InnerMap data;
99public:
100        void beginScope() { data.beginScope(); }
101        void endScope() { data.endScope(); }
102
103        /// Gets the value for the (declaration, type list) pair,
104        /// returns null if no such value exists.
105        ast::AggregateDecl const * lookup(
106                        ast::AggregateDecl const * key,
107                        type_vector const & params ) const {
108                // This type repackaging is used for the helpers.
109                ast::ptr<ast::AggregateDecl> ptr = key;
110                TypeList typeList( params );
111
112                // Scan scopes for matches to the key.
113                for ( auto insts = data.find( key ) ;
114                                insts != data.end() ; insts = data.findNext( insts, ptr )) {
115                        for ( auto inst = insts->second.rbegin() ;
116                                        inst != insts->second.rend() ; ++inst ) {
117                                if ( inst->first == typeList ) {
118                                        return inst->second;
119                                }
120                        }
121                }
122                return nullptr;
123        }
124
125        /// Adds a value for a (key, type list) pair to the current scope.
126        void insert( ast::AggregateDecl const * key, type_vector const & params,
127                        ast::AggregateDecl const * value ) {
128                auto it = data.findAt( data.currentScope(), key );
129                if ( it == data.end() ) {
130                        data.insert( key, ValueList( 1,
131                                Instantiation( TypeList( params ), value ) ) );
132                } else {
133                        it->second.emplace_back(
134                                Instantiation( TypeList( params ), value ) );
135                }
136        }
137};
138
139/// Possible options for a given specialization of a generic type.
140enum class GenericType {
141        /// Concrete instatiation based solely on {d,f}type-to-void conversions.
142        dtypeStatic,
143        /// Concrete instatiation requiring at least one parameters type.
144        concrete,
145        /// No concrete instantiation.
146        dynamic
147};
148
149GenericType & operator|=( GenericType & gt, const GenericType & ht ) {
150        if ( gt < ht ) gt = ht;
151        return gt;
152}
153
154bool isDtypeStatic( ast::vector<ast::TypeDecl> const & baseParams ) {
155        return std::all_of( baseParams.begin(), baseParams.end(),
156                []( ast::TypeDecl const * td ){ return !td->isComplete(); }
157        );
158}
159
160/// Makes substitutions of params into baseParams; returns dtypeStatic if
161/// there is a concrete instantiation based only on {d,f}type-to-void
162/// conversions, concrete if there is a concrete instantiation requiring at
163/// least one parameter type, and dynamic if there is no concrete instantiation.
164GenericType makeSubstitutions(
165                ast::vector<ast::TypeExpr> & out,
166                ast::vector<ast::TypeDecl> const & baseParams,
167                ast::vector<ast::Expr> const & params ) {
168        GenericType gt = GenericType::dtypeStatic;
169
170        // Substitute concrete types for given parameters,
171        // using incomplete types for placeholders.
172        auto baseParam = baseParams.begin();
173        auto param = params.begin();
174        for ( ; baseParam != baseParams.end() && param != params.end() ;
175                        ++baseParam, ++param ) {
176                ast::TypeExpr const * paramExpr = param->as<ast::TypeExpr>();
177                assertf( paramExpr, "Aggregate parameters should be type expressions." );
178
179                if ( (*baseParam)->isComplete() ) {
180                        // Substitute parameter for complete (otype or sized dtype) type.
181                        if ( isPolyType( paramExpr->type ) ) {
182                                // Substitute polymorphic parameter type in to generic type.
183                                out.push_back( ast::deepCopy( paramExpr ) );
184                                gt = GenericType::dynamic;
185                        } else {
186                                // Normalize possibly dtype-static parameter type.
187                                out.emplace_back( new ast::TypeExpr( paramExpr->location,
188                                        scrubAllTypeVars( ast::deepCopy( paramExpr->type ) ) ) );
189                                gt |= GenericType::concrete;
190                        }
191                } else switch ( (*baseParam)->kind ) {
192                case ast::TypeDecl::Dtype:
193                        // Here, pretend that any incomplete dtype is `void`.
194                        out.emplace_back( new ast::TypeExpr( paramExpr->location,
195                                new ast::VoidType() ) );
196                        break;
197                case ast::TypeDecl::Ftype:
198                        // Here, pretend that any ftype is `void (*)(void)`.
199                        out.emplace_back( new ast::TypeExpr( paramExpr->location,
200                                new ast::FunctionType() ) );
201                        break;
202                case ast::TypeDecl::Ttype:
203                        assertf( false, "Ttype parameters are not currently allowed as parameters to generic types." );
204                        break;
205                default:
206                        assertf( false, "Unhandled type parameter kind" );
207                        break;
208                }
209        }
210
211        assertf( baseParam == baseParams.end(), "Base Parameters not exausted." );
212        assertf( param == params.end(), "Type parameters not exausted." );
213        return gt;
214}
215
216/// Substitutes types of members according to baseParams => typeSubs,
217/// returning the result in a new vector.
218ast::vector<ast::Decl> substituteMembers(
219                ast::vector<ast::Decl> const & members,
220                ast::vector<ast::TypeDecl> const & baseParams,
221                ast::vector<ast::TypeExpr> const & typeSubs ) {
222        ast::vector<ast::Decl> out;
223        ast::TypeSubstitution subs( baseParams, typeSubs );
224        for ( ast::ptr<ast::Decl> const & member : members ) {
225                // Create a manual copy to avoid in-place mutation.
226                // If being a PureVisitor is decided to be part of apply's interface,
227                // then we can actually skip this step as it will never mutate in-
228                // place. (Then we don't need the extra guard to free temp value.)
229                ast::ptr<ast::Decl> copy = ast::deepCopy( member.get() );
230                auto result = subs.apply( copy.get() );
231                out.emplace_back( result.node );
232        }
233        return out;
234}
235
236/// Substitutes types of members according to baseParams => typeSubs,
237/// modifying them in-place.
238void substituteMembersHere(
239                ast::vector<ast::Decl> & members,
240                ast::vector<ast::TypeDecl> const & baseParams,
241                ast::vector<ast::TypeExpr> const & typeSubs ) {
242        ast::TypeSubstitution subs( baseParams, typeSubs );
243        for ( ast::ptr<ast::Decl> & member : members ) {
244                // The member must be mutated in place to avoid breaking
245                assert( member->unique() );
246
247                auto field = member.strict_as<ast::ObjectDecl>();
248                auto result = subs.apply( field->type.get() );
249                auto copy = ast::mutate_field(
250                        field, &ast::ObjectDecl::type, result.node );
251
252                // I'm not kidding, it is very important.
253                assert( copy == member.get() );
254        }
255}
256
257/// Strips the instances' type parameters.
258void stripInstParams( ast::BaseInstType * inst ) {
259        inst->params.clear();
260}
261
262bool isGenericType( ast::Type const * type ) {
263        if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
264                return !inst->params.empty();
265        } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
266                return !inst->params.empty();
267        } else {
268                return false;
269        }
270}
271
272// The Passes:
273
274struct FixDtypeStatic final :
275                public ast::WithGuards,
276                public ast::WithVisitorRef<FixDtypeStatic>,
277                public ast::WithShortCircuiting,
278                public ast::WithStmtsToAdd<> {
279        ast::ApplicationExpr const * previsit( ast::ApplicationExpr const * expr );
280        void previsit( ast::AddressExpr const * expr );
281
282        ast::Expr const * postvisit( ast::MemberExpr const * expr );
283private:
284        template<typename Aggr>
285        ast::Expr const * fixMemberExpr(
286                Aggr const * inst, ast::MemberExpr const * memberExpr );
287
288        ast::Expr const * fixMemberExpr(
289                ast::vector<ast::TypeDecl> const & baseParams,
290                ast::MemberExpr const * memberExpr );
291
292        bool isLValueArg = false;
293};
294
295ast::ApplicationExpr const * FixDtypeStatic::previsit(
296                ast::ApplicationExpr const * expr ) {
297        GuardValue( isLValueArg ) = false;
298        ast::Decl const * function = ast::getFunction( expr );
299        if ( ast::Linkage::Intrinsic != function->linkage
300                        || !CodeGen::isAssignment( function->name ) ) {
301                return expr;
302        }
303
304        // Explicity visit children because only the first element must be a
305        // C lvalue (normally, it can only send info to both or neither).
306        visit_children = false;
307        expr = mutate_field( expr, &ast::ApplicationExpr::env,
308                maybe_accept( expr->env.get(), *visitor ) );
309        expr = mutate_field( expr, &ast::ApplicationExpr::result,
310                maybe_accept( expr->result.get(), *visitor ) );
311        expr = mutate_field( expr, &ast::ApplicationExpr::func,
312                maybe_accept( expr->func.get(), *visitor ) );
313        isLValueArg = true;
314        for ( unsigned i = 0; i < expr->args.size(); ++i ) {
315                ast::Expr const * newExpr = expr->args[i]->accept( *visitor );
316                // This is declared here for lifetime reasons.
317                ast::ptr<ast::CastExpr> cast;
318                if ( newExpr != expr->args[i].get() &&
319                                (cast = dynamic_cast<ast::CastExpr const *>( newExpr )) ) {
320                        newExpr = cast->arg.get();
321                }
322                expr = mutate_field_index( expr, &ast::ApplicationExpr::args,
323                        i, newExpr );
324                isLValueArg = false;
325        }
326        return expr;
327}
328
329void FixDtypeStatic::previsit( ast::AddressExpr const * ) {
330        // The argument of an address expression (`&`) must be a C lvalue.
331        GuardValue( isLValueArg ) = true;
332}
333
334ast::Expr const * FixDtypeStatic::postvisit( ast::MemberExpr const * expr ) {
335        ast::ptr<ast::Type> const & type = expr->aggregate->result;
336        if ( !isGenericType( type ) ) {
337                return expr;
338        } else if ( auto inst = type.as<ast::StructInstType>() ) {
339                return fixMemberExpr( inst, expr );
340        } else if ( auto inst = type.as<ast::UnionInstType>() ) {
341                return fixMemberExpr( inst, expr );
342        }
343        return expr;
344}
345
346template<typename Aggr>
347ast::Expr const * FixDtypeStatic::fixMemberExpr(
348                Aggr const * inst, ast::MemberExpr const * memberExpr ) {
349        return fixMemberExpr( inst->base->params, memberExpr );
350}
351
352ast::Expr const * FixDtypeStatic::fixMemberExpr(
353                ast::vector<ast::TypeDecl> const & baseParams,
354                ast::MemberExpr const * memberExpr ) {
355        // Need to cast dtype-static member expressions to their actual type
356        // before the actual type type is erased.
357        // NOTE: The casts here have the third argument (isGenerated) set to
358        // ExplicitCast so that they casts persist until Box, where they are needed.
359
360        if ( !isDtypeStatic( baseParams ) ||
361                        ResolvExpr::typesCompatible(
362                                memberExpr->result,
363                                memberExpr->member->get_type(), ast::SymbolTable() ) ) {
364                return memberExpr;
365        }
366
367        // Type of member and type of expression differ.
368        ast::Type const * concType = ast::deepCopy( memberExpr->result );
369        CodeLocation const & location = memberExpr->location;
370        if ( isLValueArg ) {
371                // The result must be a C lvalue expression. So make a new reference
372                // variable with the correct actual type to replace the
373                // member expression.
374                //   forall(T &)
375                //   struct Ptr {
376                //     T * x;
377                //   };
378                //   Ptr(int) p;
379                //   int i;
380                // The original expression:
381                //   p.x = &i;
382                // Becomes the expression/declaration:
383                //   int *& _dtype_static_member_0;
384                //   (_dtype_static_member_0 = (int**)&p.x,
385                //    _dtype_static_member_0) = &i;
386
387                // The declaration is simple:
388                static UniqueName tmpNamer( "_dtype_static_member_" );
389                ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
390                        tmpNamer.newName(),
391                        new ast::ReferenceType( concType ),
392                        nullptr,
393                        ast::Storage::Classes(),
394                        ast::Linkage::C
395                );
396                stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
397
398                // The expression is more complex, uses references and reference /
399                // pointer parity. But breaking it up risks reordering.
400                return new ast::CommaExpr( location,
401                        ast::UntypedExpr::createAssign( location,
402                                new ast::VariableExpr( location, tmp ),
403                                new ast::CastExpr( location,
404                                        new ast::AddressExpr( location, memberExpr ),
405                                        new ast::PointerType( ast::deepCopy( concType ) ),
406                                        ast::ExplicitCast
407                                )
408                        ),
409                        new ast::VariableExpr( location, tmp )
410                );
411        } else {
412                // Here, it can simply add a cast to actual types.
413                return new ast::CastExpr( location,
414                        memberExpr,
415                        concType,
416                        ast::ExplicitCast
417                );
418        }
419}
420
421struct GenericInstantiator final :
422                public ast::WithCodeLocation,
423                public ast::WithConstTypeSubstitution,
424                public ast::WithDeclsToAdd<>,
425                public ast::WithGuards,
426                public ast::WithVisitorRef<GenericInstantiator>
427{
428        /// Map of (generic type, parameter list) pairs
429        /// to concrete type instantiations.
430        InstantiationMap instantiations;
431        /// Set of types which are dtype-only generic
432        /// (and therefore have static layout).
433        std::set<ast::AggregateDecl const *> dtypeStatics;
434        /// Namer for concrete types.
435        UniqueName typeNamer;
436        /// Should not make use of type environment to replace types of function
437        /// parameter and return values.
438        bool inFunctionType = false;
439        /// Index of current member, used to recreate MemberExprs with the
440        /// member from an instantiation.
441        int memberIndex = -1;
442
443        GenericInstantiator() :
444                instantiations(), dtypeStatics(), typeNamer("_conc_") {}
445
446        ast::Type const * postvisit( ast::StructInstType const * inst );
447        ast::Type const * postvisit( ast::UnionInstType const * inst );
448
449        void previsit( ast::MemberExpr const * expr );
450        ast::Expr const * postvisit( ast::MemberExpr const * expr );
451        ast::Expr const * postvisit( ast::Expr const * expr );
452        void previsit( ast::ParseNode const * node );
453
454        void previsit( ast::FunctionType const * ) {
455                GuardValue( inFunctionType ) = true;
456        }
457        void beginScope() {
458                instantiations.beginScope();
459        }
460        void endScope() {
461                instantiations.endScope();
462        }
463private:
464        /// Wrap instantiation lookup for structures.
465        ast::StructDecl const * lookup(
466                ast::StructInstType const * inst, type_vector const & typeSubs ) const;
467        /// Wrap instantiation lookup for unions.
468        ast::UnionDecl const * lookup(
469                ast::UnionInstType const * inst, type_vector const & typeSubs ) const;
470        /// Wrap instantiation insertion for structures.
471        void insert( ast::StructInstType const * inst,
472                type_vector const & typeSubs, ast::StructDecl const * decl );
473        /// Wrap instantiation insertion for unions.
474        void insert( ast::UnionInstType const * inst,
475                type_vector const & typeSubs, ast::UnionDecl const * decl );
476
477        void replaceParametersWithConcrete( ast::vector<ast::Expr> & params );
478        ast::Type const * replaceWithConcrete( ast::Type const * type, bool doClone );
479
480        template<typename AggrDecl>
481        ast::Type const * fixInstType( ast::SueInstType<AggrDecl> const * inst );
482
483        /// Strips a dtype-static aggregate decl of its type parameters,
484        /// marks it as stripped.
485        void stripDtypeParams( ast::AggregateDecl * base,
486                ast::vector<ast::TypeDecl> & baseParams,
487                ast::vector<ast::TypeExpr> const & typeSubs );
488};
489
490ast::Type const * GenericInstantiator::postvisit(
491                ast::StructInstType const * inst ) {
492        return fixInstType( inst );
493}
494
495ast::Type const * GenericInstantiator::postvisit(
496                ast::UnionInstType const * inst ) {
497        return fixInstType( inst );
498}
499
500template<typename AggrDecl>
501ast::Type const * GenericInstantiator::fixInstType(
502                ast::SueInstType<AggrDecl> const * inst ) {
503        assert( location );
504
505        // There is nothing to mutate if the params are empty.
506        if ( inst->params.empty() ) return inst;
507
508        // Need to replace type variables to ensure that generic types are
509        // instantiated for the return values of polymorphic functions (in
510        // particular, for thunks, because they are not [currently] copy
511        // constructed).
512        // (This used to be run only on structures, but I believe both need it.)
513        inst = strict_dynamic_cast<ast::SueInstType<AggrDecl> const *>(
514                replaceWithConcrete( inst, false ) );
515
516        // Check for an already-instantiatiated dtype-static type.
517        if ( dtypeStatics.find( inst->base ) != dtypeStatics.end() ) {
518                auto mutInst = ast::mutate( inst );
519                stripInstParams( mutInst );
520                return mutInst;
521        }
522
523        // Check if the type can be concretely instantiated;
524        // and put substitutions in typeSubs.
525        assertf( inst->base, "Base data-type has parameters." );
526        ast::vector<ast::TypeExpr> typeSubs;
527        GenericType gt = makeSubstitutions( typeSubs, inst->base->params, inst->params );
528        switch ( gt ) {
529        case GenericType::dtypeStatic:
530        {
531                auto mutInst = ast::mutate( inst );
532                assert( mutInst->base->unique() );
533                auto mutBase = mutInst->base.get_and_mutate();
534                stripDtypeParams( mutBase, mutBase->params, typeSubs );
535                stripInstParams( mutInst );
536                return mutInst;
537        }
538        case GenericType::concrete:
539        {
540                // Make concrete instantiation of generic type.
541                AggrDecl const * concDecl = lookup( inst, typeSubs );
542                if ( !concDecl ) {
543                        // Set concDecl to new type, insert type declaration
544                        // into statements to add.
545                        AggrDecl * newDecl = new AggrDecl( *location,
546                                typeNamer.newName( inst->name )
547                        );
548                        newDecl->body = inst->base->body;
549                        newDecl->members = substituteMembers(
550                                inst->base->members,
551                                inst->base->params,
552                                typeSubs
553                        );
554
555                        // Forward declare before recursion. (TODO: Only when needed, #199.)
556                        insert( inst, typeSubs, newDecl );
557                        if ( AggrDecl const * forwardDecl = ast::asForward( newDecl ) ) {
558                                declsToAddBefore.push_back( forwardDecl );
559                        }
560                        // Recursively instantiate members:
561                        concDecl = strict_dynamic_cast<AggrDecl const *>(
562                                newDecl->accept( *visitor ) );
563                        // Must occur before declaration is added so
564                        // that member instantiation appear first.
565                        declsToAddBefore.push_back( concDecl );
566                }
567                return new ast::SueInstType<AggrDecl>( concDecl, inst->qualifiers );
568        }
569        case GenericType::dynamic:
570                // Do nothing.
571        default:
572                // Should never happen.
573                return inst;
574        }
575}
576
577void GenericInstantiator::previsit( ast::MemberExpr const * expr ) {
578        GuardValue( location ) = &expr->location;
579        GuardValue( memberIndex ) = -1;
580        // Only run on expressions where the field being accessed is generic.
581        if ( isGenericType( expr->aggregate->result ) ) {
582                // Find the location of the member:
583                ast::AggregateDecl const * aggr =
584                        expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
585                ast::vector<ast::Decl> const & members = aggr->members;
586                auto it = std::find( members.begin(), members.end(), expr->member );
587                memberIndex = std::distance( members.begin(), it );
588                assertf( memberIndex < (int)members.size(), "Could not find member %s in generic type %s.", toString( expr->member ).c_str(), toString( expr->aggregate ).c_str() );
589        }
590}
591
592ast::Expr const * GenericInstantiator::postvisit(
593                ast::MemberExpr const * expr ) {
594        if ( memberIndex == -1 ) {
595                return expr;
596        }
597
598        // Using the location from the generic type, find the member
599        // in the instantiation and rebuild the member expression.
600        ast::AggregateDecl const * aggr =
601                expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
602        assertf( memberIndex < (int)aggr->members.size(), "Instantiation somehow has fewer members than the generic type." );
603        ast::Decl const * member = *std::next( aggr->members.begin(), memberIndex );
604        assertf( member->name == expr->member->name, "Instantiation has different member order than the generic type. %s / %s", toString( member ).c_str(), toString( expr->member ).c_str() );
605        auto field = strict_dynamic_cast< ast::DeclWithType const * >( member );
606        ast::MemberExpr * ret = new ast::MemberExpr( expr->location,
607                field,
608                ast::deepCopy( expr->aggregate )
609        );
610        // For pointer decay:
611        ret->result = ResolvExpr::adjustExprType(
612                ret->result,
613                ast::TypeEnvironment(),
614                ast::SymbolTable()
615        );
616        ret->env = expr->env;
617        return ret;
618}
619
620ast::Expr const * GenericInstantiator::postvisit( ast::Expr const * expr ) {
621        // We are not modifying env on MemberExpr, but that seems to work.
622        if ( expr->env ) {
623                auto newEnv = expr->env->accept( *visitor );
624                expr = ast::mutate_field( expr, &ast::Expr::env, newEnv );
625        }
626        return expr;
627}
628
629void GenericInstantiator::previsit( ast::ParseNode const * node ) {
630        GuardValue( location ) = &node->location;
631}
632
633ast::StructDecl const * GenericInstantiator::lookup(
634                ast::StructInstType const * inst,
635                type_vector const & typeSubs ) const {
636        auto ret = instantiations.lookup( inst->base, typeSubs );
637        return strict_dynamic_cast<ast::StructDecl const *, nullptr>( ret );
638}
639
640ast::UnionDecl const * GenericInstantiator::lookup(
641                ast::UnionInstType const * inst,
642                type_vector const & typeSubs ) const {
643        auto ret = instantiations.lookup( inst->base, typeSubs );
644        return strict_dynamic_cast<ast::UnionDecl const *, nullptr>( ret );
645}
646
647void GenericInstantiator::insert( ast::StructInstType const * inst,
648                type_vector const & typeSubs, ast::StructDecl const * decl ) {
649        instantiations.insert( inst->base, typeSubs, decl );
650}
651
652void GenericInstantiator::insert( ast::UnionInstType const * inst,
653                type_vector const & typeSubs, ast::UnionDecl const * decl ) {
654        instantiations.insert( inst->base, typeSubs, decl );
655}
656
657void GenericInstantiator::replaceParametersWithConcrete(
658                ast::vector<ast::Expr> & params ) {
659        for ( ast::ptr<ast::Expr> & param : params ) {
660                auto paramType = param.as<ast::TypeExpr>();
661                assertf( paramType, "Aggregate parameters should be type expressions." );
662                auto type = replaceWithConcrete( paramType->type, false );
663                param = ast::mutate_field( paramType, &ast::TypeExpr::type, type );
664        }
665}
666
667ast::Type const * GenericInstantiator::replaceWithConcrete(
668                ast::Type const * type, bool doClone ) {
669        if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
670                if ( typeSubs && !inFunctionType ) {
671                        ast::Type const * concType = typeSubs->lookup( inst );
672                        return ast::deepCopy( ( concType ) ? concType : inst );
673                }
674        } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
675                auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
676                replaceParametersWithConcrete( mut->params );
677                return mut;
678        } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
679                auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
680                replaceParametersWithConcrete( mut->params );
681                return mut;
682        }
683        return type;
684}
685
686void GenericInstantiator::stripDtypeParams(
687                ast::AggregateDecl * base,
688                ast::vector<ast::TypeDecl> & baseParams,
689                ast::vector<ast::TypeExpr> const & typeSubs ) {
690        substituteMembersHere( base->members, baseParams, typeSubs );
691
692        baseParams.clear();
693
694        dtypeStatics.insert( base );
695}
696
697} // namespace
698
699void instantiateGeneric( ast::TranslationUnit & translationUnit ) {
700        ast::Pass<FixDtypeStatic>::run( translationUnit );
701        ast::Pass<GenericInstantiator>::run( translationUnit );
702}
703
704} // namespace GenPoly
705
706// Local Variables: //
707// tab-width: 4 //
708// mode: c++ //
709// compile-command: "make install" //
710// End: //
Note: See TracBrowser for help on using the repository browser.