summaryrefslogblamecommitdiff
path: root/sources/scalac/transformer/ExpandMixinsPhase.java
blob: 01a99aa897ea2e7ddba9214541ea150bdf3be2ec (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11



                                                                          






                                                                          

                         
 
                     

                              




                                
                           


                            
 






                                                                    
                                              



                                                                              
                                                
                                                    

                                                        
                                                      

                                                                     
                                                     
                                                      
                                      

                                                              
                                       

                                                                              










                                                                           

     

                                                                              
 
                                     

                                  
                                                       
     
 



                                                                             























                                                                               
                    
     
 



                                                                              
                                                                           











                                                                           
                                                                            
                                         



                                                     


                                                      



                                                                               
                                      


























                                                                              

                                      
                                                                              



                                             




                                                                      
                                                                       










                                                                              
 
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $OldId: ExpandMixinsPhase.java,v 1.8 2002/05/02 10:59:35 schinz Exp $
// $Id$

package scalac.transformer;

import java.util.Map;
import java.util.HashMap;

import scalac.Global;
import scalac.Phase;
import scalac.PhaseDescriptor;
import scalac.Unit;
import scalac.ast.Tree;
import scalac.ast.Tree.Template;
import scalac.ast.Traverser;
import scalac.ast.Transformer;
import scalac.symtab.Scope;
import scalac.symtab.Symbol;
import scalac.symtab.Type;
import scalac.util.Debug;

// TODO do not copy hidden members which are not accessible via
// "super".

/**
 * A phase to expand mixins using code copying. We assume that links
 * to outer classes have been made explicit by a previous phase.
 */
public class ExpandMixinsPhase extends Phase {

    //########################################################################
    // Private Fields

    /** A map from classes to their interface */
    private final Map/*<Symbol,Symbol>*/ interfaces;

    /** A map from classes to their expanded template */
    private final Map/*<Symbol,Template>*/ expansions;

    /** A map from classes to their original (unexpanded) template */
    private final Map/*<Symbol,Template>*/ templates;
    /** A traverser that collects class definitions */
    private final Traverser collector;

    /** A transformer that expands classes that have mixins */
    private final Transformer expander;

    //########################################################################
    // Public Constructors

    /** Initializes this instance. */
    public ExpandMixinsPhase(Global global, PhaseDescriptor descriptor) {
        super(global, descriptor);
        Phase addinterfaces = global.PHASE.ADDINTERFACES.phase();
        this.interfaces = ((AddInterfacesPhase)addinterfaces).classToIFace;
        this.expansions = new HashMap();
        this.templates = new HashMap();
        this.collector = new Collector();
        this.expander = new Expander(global);
    }

    //########################################################################
    // Public Methods

    public void apply(Unit[] units) {
        collector.traverse(units);
        expander.apply(units);
        assert templates.isEmpty(): templates.keySet();
    }

    public Type transformInfo(Symbol symbol, Type type) {
        // !!! make this work and remove *1 in ClassExpander
        // if (!symbol.isJava() && symbol.isClass() && !symbol.isInterface())
        //     type = getExpandedTemplate(symbol).type();
        if (symbol.isClass() && !symbol.isInterface()) {
            switch (type) {
            case CompoundType(Type[] parents, Scope members):
                Type[] types = parents;
                for (int i = 1; i < parents.length; i++) {
                    switch (parents[i]) {
                    case TypeRef(Type prefix, Symbol parent, Type[] args):
                        if (parent.isInterface()) continue;
                        if (types == parents) types = Type.cloneArray(parents);
                        parent = (Symbol)interfaces.get(parent);
                        assert parent != null: parents[i];
                        types[i] = Type.TypeRef(prefix, parent, args);
                        continue;
                    default:
                        throw Debug.abort("illegal case", parents[i]);
                    }
                }
                if (types != parents)
                    type = Type.compoundType(types, members, symbol);
                break;
            default:
                throw Debug.abort("illegal case", type);
            }
        }
        return type;
    }

    //########################################################################
    // Private Methods

    private Template getExpandedTemplate(Symbol clasz) {
	assert Debug.log("get expanded " + clasz + " in " + clasz.owner());
        Template template = (Template)expansions.get(clasz);
        if (template == null) {
            template = (Template)templates.remove(clasz);
            assert template != null : Debug.show(clasz);
            template = expandTemplate(clasz, expander.transform(template));
            expansions.put(clasz, template);
        }
        return template;
    }

    private Template expandTemplate(Symbol clasz, Template template) {
        assert Debug.log("expanding ", clasz);
        ClassExpander expander = new ClassExpander(global, clasz, template);
        Type[] parents = clasz.parents();
        // force expansion of superclass
        if (!parents[0].symbol().isExternal())
            getExpandedTemplate(parents[0].symbol());
        // inline mixins
        for (int i = parents.length - 1; i > 0; --i) {
            Symbol parent = parents[i].symbol();
            if (parent.isInterface()) continue;
            assert Debug.log("expanding ", clasz, ": inlining ", parent);
            expander.inlineMixin(i, parents[i], (Symbol)interfaces.get(parent),
                getExpandedTemplate(parent));
        }
        return expander.getTemplate();
    }

    //########################################################################
    // Private Class - Collector

    private class Collector extends Traverser {
        public void traverse(Tree tree) {
            switch(tree) {
            case ClassDef(_, _, _, _, _, Template template):
                Symbol clasz = tree.symbol();
                if (!clasz.isInterface()) templates.put(clasz, template);
                traverse(template.body);
                return;
            case PackageDef(_, Template(_, Tree[] body)):
                traverse(body);
                return;
            }
        }
    }

    //########################################################################
    // Private Class - Expander

    private class Expander extends Transformer {
        public Expander(Global global) {
            super(global);
        }
        public void apply(Unit unit) {
            if (unit.mixinOnly) {
                assert Debug.log("removing " +unit+ " after mixin expansion");
                unit.body = Tree.EMPTY_ARRAY;
            } else
                super.apply(unit);
        }
        public Tree transform(Tree tree) {
            switch (tree) {
            case ClassDef(_, _, _, _, _, _):
                Symbol clasz = tree.symbol();
                if (clasz.isInterface()) return super.transform(tree);
                return gen.ClassDef(clasz, getExpandedTemplate(clasz));
            case PackageDef(_, _):
                return super.transform(tree);
            case Template(_, _):
                return super.transform(tree);
            default:
                return tree;
            }
        }
    }

    //########################################################################
}