source: src/GenPoly/InstantiateGenericNew.cpp @ 7e4bd9b6

Last change on this file since 7e4bd9b6 was 251ce80, checked in by Fangren Yu <f37yu@…>, 17 months ago

remove reference to symbol table in unify

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