#include #include "../AST.h" #include "../FlattenContext.h" #include "../TypeContext.h" #include "../compiler.h" #include "../streq.h" #include "Instantiations.h" #include "PseudonymDecl.h" #include "../tclimits.h" bool debug_instantiation = false; //////////////////////////////////////////////////////////////////////// ClassDecl *ClassDecl::instantiateDecl( TreeListNode &actuals, int depth ) { assert( instantiations != NULL ); TypeDeclNode &basis = static_cast< TypeDeclNode & >( *source() ); TreeListNode &formals = *basis.parent()->params(); assert( basis.decl() == this ); const int numFormals = formals.arity(); const int numActuals = actuals.arity(); assert( numFormals == numActuals ); ////////////////////////////////////////////////////////////////////// // // The instantiation appears to be valid, provided that subsequent // constant folding reduces all actual expression parameters to // constant expressions. For now, we can go ahead and return a // real decl. // ClassDecl *&instDecl = (*instantiations)[ actuals ]; if (!instDecl) { instDecl = new ClassDecl( *this, actuals, depth ); numInstantiations++; } return instDecl; // ////////////////////////////////////////////////////////////////////// } ClassDecl::ClassDecl( ClassDecl &basis, TreeListNode &actuals, int depth ) : TypeDecl( basis.name(), // PR581: ensure ClassDecl::asType() is correct for an instantiated template // invalid( basis.name() ) new TemplateInstanceTypeNode ( new TypeNameNode (new NameNode (TreeNode::omitted, basis.name(), &basis)), appendTreeList(&actuals, NULL), this) ), instantiations( 0 ), numInstantiations( 0 ), templateActuals( &actuals ), templateBasis( &basis ), templateDepth( depth ), _container( basis.container() ), _modifiers( basis.modifiers() ), _source( 0 ), _environ( 0 ), _superClass( 0 ), _interfaces( 0 ), _valid( false ) { assert( depth > 0 ); if (debug_instantiation) cerr << "instantiate decl at depth " << depth << ':' << endl << "\tbasis decl: " << &basis << ": " << basis.errorName() << endl << "\tinst decl: " << this << ": " << errorName() << endl; } void ClassDecl::instantiateSource() { ClassDecl &basisDecl = *templateBasis; assert( basisDecl.source() != NULL ); assert( !source() ); assert( basisDecl.instantiations != NULL ); assert( templateActuals != NULL ); TypeDeclNode &basisSource = static_cast< TypeDeclNode & >(*basisDecl.source()); TemplateDeclNode &basisTemplate = static_cast< TemplateDeclNode & >(*basisSource.parent()); CompileUnitNode &basisUnit = static_cast< CompileUnitNode & >(*basisTemplate.parent()->parent()); assert( streq( basisUnit.oper_name(), "CompileUnitNode" ) ); TreeListNode &formals = *basisTemplate.params(); TreeListNode &actuals = *templateActuals; const int numFormals = formals.arity(); const int numActuals = actuals.arity(); assert( numFormals == numActuals ); Environ * const instEnv = new Environ( basisUnit.environ() ); instEnv->add( this ); for (int arg = 0; arg < numActuals; ++arg) instEnv->add( formals.child( arg )->bindPseudonym( *actuals.child( arg ) ) ); TypeDeclNode * const instSource = basisSource.deepClone(); TemplateInstanceDeclNode * const instDeclNode = new TemplateInstanceDeclNode( instSource, instEnv, instSource->position() ); CompileUnitNode &instUnit = *basisUnit.clone(); instUnit.types( instDeclNode ); // Addition to facilitate inner class changes. Should be fine since each // template instantiation has its own CompileUnitNode. instUnit.environ(instEnv); source( instSource ); instSource->simpName()->decl( this ); assert( !_environ ); _environ = new Environ( instEnv ); if (debug_instantiation) cerr << "instantiate source:" << endl << "\tbasis decl: " << &basisDecl << ": " << basisDecl.errorName() << endl << "\tinst decl: " << this << ": " << errorName() << endl << "\tbasis source: " << &basisUnit << " --> (list) --> " << &basisSource << endl << "\tinst source: " << &instUnit << " --> " << instDeclNode << " --> " << instSource << endl; // More inner class changes. // Since a template instance gets its own compile unit, inner classes must // be flattened into a separate compile unit. CompileUnitNode &innerUnit = *instUnit.clone(); llist *tmp = NULL; llist *finals = NULL; TreeNode::FlattenContext ctx(finals); ctx.toplevel = &innerUnit; ctx.inTemplate = true; innerUnit.types(new TreeListNode(tmp)); instUnit.flattenClasses(&ctx); // The template instance's compile unit has already undergone package // resolution, so doing so again would result in multiply imported and // multiply defined types. But when it previously underwent package // resolution (as the basis), the resolution was stopped at the class level. // So resolution must be done again for the lower levels, and we skip // import resolution by calling resolvePackage() directly on the // instantiated class. (Package resolution has checks to defend against // multiply defining the instance.) // Yuck. TreeNode::resolvePackage() is protected, so we need to cast. if (instSource->decl()->category() == Class) static_cast(instSource)->resolvePackage( 0, instUnit.environ(), 0, 1 ); else static_cast(instSource)->resolvePackage( 0, instUnit.environ(), 0, 1 ); innerUnit.resolvePackage( 0, 0, 0, 0 ); bool postponed = false, postponed2 = false; TreeNode::TypeContext tctx(postponed), tctx2(postponed2); instUnit.buildTypeEnv( &tctx ); innerUnit.buildTypeEnv( &tctx2 ); instUnit.resolveTypes( &tctx ); innerUnit.resolveTypes( &tctx2 ); instUnit.loaded(!postponed); innerUnit.loaded(!postponed2); } // Local Variables: // c-file-style: "gnu" // End: