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

// $OldId: ExpandMixins.java,v 1.24 2002/11/11 16:08:50 schinz Exp $
// $Id$

package scalac.transformer;

import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Iterator;

import scalac.Global;
import scalac.ast.Tree;
import scalac.ast.Tree.Template;
import scalac.ast.TreeList;
import scalac.ast.TreeGen;
import scalac.ast.TreeCloner;
import scalac.ast.TreeSymbolCloner;
import scalac.ast.Transformer;
import scalac.symtab.Modifiers;
import scalac.symtab.Scope;
import scalac.symtab.Scope.SymbolIterator;
import scalac.symtab.Symbol;
import scalac.symtab.SymbolCloner;
import scalac.symtab.SymbolSubstTypeMap;
import scalac.symtab.Type;
import scalac.util.Name;
import scalac.util.Debug;

public class ClassExpander {

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

    /** The global environment */
    private final Global global;

    /** A tree generator */
    private final TreeGen gen;

    /** The expanding class */
    private final Symbol clasz;

    /** The parents of the expanding class */
    private final Type[] parents;

    /** The members of the expanding class */
    private final Scope members;

    /** The template of the expanding class */
    private final Template template;

    /** The body of the expanding class */
    private final LinkedList/*<Tree>*/ body;

    /** The type map to apply to inlined symbols and trees */
    private final SymbolSubstTypeMap map;

    /** The symbol cloner to clone inlined symbols */
    private final SymbolCloner cloner;

    /** The state of this class (used to prevent misuses) */
    private int state;

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

    public ClassExpander(Global global, Symbol clasz, Template template) {
        this.global = global;
        this.gen = global.treeGen;
        this.clasz = clasz;
        this.parents = Type.cloneArray(clasz.parents());
        this.members = clasz.members().cloneScope();
        this.template = gen.Template(template.pos, template.symbol(),
            Tree.cloneArray(template.parents), template.body);
        this.body = new LinkedList();
        this.map = new SymbolSubstTypeMap();
        this.cloner = new SymbolCloner(
            global.freshNameCreator, new HashMap(), map.getSymbols());
        this.state = parents.length;
    }

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

    public void inlineMixin(int i, Type type, Symbol iface, Template impl) {
        assert 0 < i && i < state : "state = " + state + ", i = " + i;
        switch (parents[i]) {
        case TypeRef(Type prefix, Symbol mixin, Type[] args):
            map.insertSymbol(mixin, clasz);
            cloner.owners.put(mixin.primaryConstructor(), clasz);
            inlineMixinTParams(type);
            Tree.Apply constr = (Tree.Apply)template.parents[i];
            Symbol[] vparams = mixin.valueParams();
            inlineMixinVParams(vparams, constr.args, 0);
            handleMixinInterfaceMembers(mixin);
            inlineMixinMembers(mixin.nextInfo().members(), impl, vparams.length);
            parents[i] = Type.TypeRef(prefix, iface, args);
            template.parents[i] = gen.mkPrimaryConstr(constr.pos, parents[i]);
            state = i;
            return;
        default:
            throw Debug.abort("invalid base class type", parents[i]);
        }
    }

    public Template getTemplate() {
        assert 0 < state : "state = " + state;
        Transformer superFixer = new Transformer(global) {
            public Tree transform(Tree tree) {
                switch (tree) {
                case Select(Super(_, _), _):
                    Symbol symbol = map.lookupSymbol(tree.symbol());
                    if (symbol != null)
                        return gen.Select(gen.This(tree.pos, clasz), symbol);
                }
                return super.transform(tree);
            }
        };
        body.addAll(Arrays.asList(superFixer.transform(template.body)));
        template.body = (Tree[])body.toArray(new Tree[body.size()]);
        // !!! *1 fix ExpandMixinsPhase.transformInfo and remove next line
        clasz.updateInfo(Type.compoundType(parents, members, clasz));
        state = 0;
        return template;
    }

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

    private void inlineMixinTParams(Type type) {
        switch (type) {
        case TypeRef(Type prefix, Symbol symbol, Type[] args):
            map.insertType(symbol.typeParams(), args);
            return;
        default:
            throw Debug.abort("illegal case", type);
        }
    }

    private void inlineMixinVParams(Symbol[] params, Tree[] args, int fstPos) {
        for (int i = 0; i < params.length; i++) {
            Symbol member = cloner.cloneSymbol(params[i], true);
            member.flags &= ~Modifiers.PARAM;
            member.flags |= Modifiers.PRIVATE;
            members.enter(member);
        }
        // We need two loops because parameters may appear in their types.
        for (int i = 0; i < params.length; i++) {
            Symbol member = map.lookupSymbol(params[i]);
            member.setType(map.apply(member.type()));
            body.add(fstPos + i, gen.ValDef(member, args[i]));
        }
    }

    // !!! This is just rapid fix. Needs to be reviewed.
    private void handleMixinInterfaceMembers(Symbol mixin) {
        Type[] parents = mixin.info().parents();
        //assert parents.length == 2: Debug.show(mixin) +" -- "+ mixin.info();
        for (int i = 1; i < parents.length; i++)
            handleMixinInterfaceMembersRec(parents[i].symbol());
    }
    private void handleMixinInterfaceMembersRec(Symbol interfase) {
        handleMixinInterfaceMembersAux(interfase.nextInfo().members());
        Type[] parents = interfase.parents();
        for (int i = 0; i < parents.length; i++) {
            Symbol clasz = parents[i].symbol();
            if (clasz.isInterface()) handleMixinInterfaceMembersRec(clasz);
        }
    }
    private void handleMixinInterfaceMembersAux(Scope symbols) {
        for (SymbolIterator i = symbols.iterator(true); i.hasNext();) {
            Symbol member = i.next();
            if (member.kind != scalac.symtab.Kinds.TYPE) continue;
            // !!! use same trick as in erasure?
            //Symbol clone = member.cloneSymbol(clasz);
            //clone.setInfo(clasz.thisType().memberInfo(member));
            //Symbol subst = clasz.thisType().memberType(clone).symbol();
            Symbol subst = clasz.thisType().memberType(member).symbol();
            if (subst == member) continue;
            Symbol subst1 = map.lookupSymbol(member);
            assert subst1 == null || subst1 == subst:
                Debug.show(member," -> ",subst," + ",subst1);
            if (subst1 == null) map.insertSymbol(member, subst);
        }
    }

    private void inlineMixinMembers(Scope symbols, Template mixin, int fstPos) {
        // The map names is used to implement an all or nothing
        // strategy for overloaded symbols.
        Map/*<Name,Name>*/ names = new HashMap();
        for (SymbolIterator i = symbols.iterator(true); i.hasNext();) {
            Symbol member = i.next();
            Name name = (Name)names.get(member.name);
            boolean shadowed = name == null &&
                members.lookup(member.name) != Symbol.NONE;
            Symbol clone = cloner.cloneSymbol(member, shadowed);
            if (name != null)
                clone.name = name;<commit_msg>- Added outer type links to rebound abstract types<commit_after>/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $OldId: ExpandMixins.java,v 1.24 2002/11/11 16:08:50 schinz Exp $
// $Id$

package scalac.transformer;

import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Iterator;

import scalac.Global;
import scalac.ast.Tree;
import scalac.ast.Tree.Template;
import scalac.ast.TreeList;
import scalac.ast.TreeGen;
import scalac.ast.TreeCloner;
import scalac.ast.TreeSymbolCloner;
import scalac.ast.Transformer;
import scalac.symtab.Modifiers;
import scalac.symtab.Scope;
import scalac.symtab.Scope.SymbolIterator;
import scalac.symtab.Symbol;
import scalac.symtab.SymbolCloner;
import scalac.symtab.SymbolSubstTypeMap;
import scalac.symtab.Type;
import scalac.util.Name;
import scalac.util.Debug;

public class ClassExpander {

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

    /** The global environment */
    private final Global global;

    /** A tree generator */
    private final TreeGen gen;

    /** The expanding class */
    private final Symbol clasz;

    /** The parents of the expanding class */
    private final Type[] parents;

    /** The members of the expanding class */
    private final Scope members;

    /** The template of the expanding class */
    private final Template template;

    /** The body of the expanding class */
    private final LinkedList/*<Tree>*/ body;

    /** The type map to apply to inlined symbols and trees */
    private final SymbolSubstTypeMap map;

    /** The symbol cloner to clone inlined symbols */
    private final SymbolCloner cloner;

    /** The state of this class (used to prevent misuses) */
    private int state;

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

    public ClassExpander(Global global, Symbol clasz, Template template) {
        this.global = global;
        this.gen = global.treeGen;
        this.clasz = clasz;
        this.parents = Type.cloneArray(clasz.parents());
        this.members = clasz.members().cloneScope();
        this.template = gen.Template(template.pos, template.symbol(),
            Tree.cloneArray(template.parents), template.body);
        this.body = new LinkedList();
        this.map = new SymbolSubstTypeMap();
        this.cloner = new SymbolCloner(
            global.freshNameCreator, new HashMap(), map.getSymbols());
        this.state = parents.length;
    }

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

    public void inlineMixin(int i, Type type, Symbol iface, Template impl) {
        assert 0 < i && i < state : "state = " + state + ", i = " + i;
        switch (parents[i]) {
        case TypeRef(Type prefix, Symbol mixin, Type[] args):
            map.insertSymbol(mixin, clasz);
            cloner.owners.put(mixin.primaryConstructor(), clasz);
            inlineMixinTParams(type);
            Tree.Apply constr = (Tree.Apply)template.parents[i];
            Symbol[] vparams = mixin.valueParams();
            inlineMixinVParams(vparams, constr.args, 0);
            handleMixinInterfaceMembers(mixin);
            inlineMixinMembers(mixin.nextInfo().members(), impl, vparams.length);
            parents[i] = Type.TypeRef(prefix, iface, args);
            template.parents[i] = gen.mkPrimaryConstr(constr.pos, parents[i]);
            state = i;
            return;
        default:
            throw Debug.abort("invalid base class type", parents[i]);
        }
    }

    public Template getTemplate() {
        assert 0 < state : "state = " + state;
        Transformer superFixer = new Transformer(global) {
            public Tree transform(Tree tree) {
                switch (tree) {
                case Select(Super(_, _), _):
                    Symbol symbol = map.lookupSymbol(tree.symbol());
                    if (symbol != null)
                        return gen.Select(gen.This(tree.pos, clasz), symbol);
                }
                return super.transform(tree);
            }
        };
        body.addAll(Arrays.asList(superFixer.transform(template.body)));
        template.body = (Tree[])body.toArray(new Tree[body.size()]);
        // !!! *1 fix ExpandMixinsPhase.transformInfo and remove next line
        clasz.updateInfo(Type.compoundType(parents, members, clasz));
        state = 0;
        return template;
    }

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

    private void inlineMixinTParams(Type type) {
        switch (type) {
        case TypeRef(Type prefix, Symbol symbol, Type[] args):
            map.insertType(symbol.typeParams(), args);
            return;
        default:
            throw Debug.abort("illegal case", type);
        }
    }

    private void inlineMixinVParams(Symbol[] params, Tree[] args, int fstPos) {
        for (int i = 0; i < params.length; i++) {
            Symbol member = cloner.cloneSymbol(params[i], true);
            member.flags &= ~Modifiers.PARAM;
            member.flags |= Modifiers.PRIVATE;
            members.enter(member);
        }
        // We need two loops because parameters may appear in their types.
        for (int i = 0; i < params.length; i++) {
            Symbol member = map.lookupSymbol(params[i]);
            member.setType(map.apply(member.type()));
            body.add(fstPos + i, gen.ValDef(member, args[i]));
        }
    }

    // !!! This is just rapid fix. Needs to be reviewed.
    private void handleMixinInterfaceMembers(Symbol mixin) {
        Type[] parents = mixin.info().parents();
        //assert parents.length == 2: Debug.show(mixin) +" -- "+ mixin.info();
        for (int i = 1; i < parents.length; i++)
            handleMixinInterfaceMembersRec(parents[i].symbol());
    }
    private void handleMixinInterfaceMembersRec(Symbol interfase) {
        handleMixinInterfaceMembersAux(interfase.nextInfo().members());
        Type[] parents = interfase.parents();
        for (int i = 0; i < parents.length; i++) {
            Symbol clasz = parents[i].symbol();
            if (clasz.isInterface()) handleMixinInterfaceMembersRec(clasz);
        }
    }
    private void handleMixinInterfaceMembersAux(Scope symbols) {
        for (SymbolIterator i = symbols.iterator(true); i.hasNext();) {
            Symbol member = i.next();
            if (!member.isAbstractType()) continue;
            // !!! use same trick as in erasure?
            //Symbol clone = member.cloneSymbol(clasz);
            //clone.setInfo(clasz.thisType().memberInfo(member));
            //Symbol subst = clasz.thisType().memberType(clone).symbol();
            Symbol subst = clasz.thisType().memberType(member).symbol();
            if (subst == member) continue;
            Type subst1 = map.lookupType(member);
            assert subst1 == null || subst1.symbol() == subst:
                Debug.show(member," -> ",subst," + ",subst1);
            if (subst1 == null) {
                Type prefix = Type.localThisType;
                // compute outer type links of subst
                Type[] args = Symbol.type(subst.owner().typeParams());
                args = Type.asSeenFrom(args, clasz.thisType(), subst.owner());
                map.insertType(member, Type.TypeRef(prefix, subst, args));
            }
        }
    }

    private void inlineMixinMembers(Scope symbols, Template mixin, int fstPos) {
        // The map names is used to implement an all or nothing
        // strategy for overloaded symbols.
        Map/*<Name,Name>*/ names = new HashMap();
        for (SymbolIterator i = symbols.iterator(true); i.hasNext();) {
            Symbol member = i.next();
            Name name = (Name)names.get(member.name);
            boolean shadowed = name == null &&
                members.lookup(member.name) != Symbol.NONE;
            Symbol clone = cloner.cloneSymbol(member, shadowed);
            if (name != null)
                clone.name = name;
{'fraction_non_alphanumeric': 0.152145174858791, 'fraction_numerical': 0.004326403076553299, 'mean_word_length': 2.2253875968992247, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2880353', 'n_tokens_mistral': 4600, 'n_tokens_neox': 4487, 'n_words': 1124}