<commit_before>package polyglot.ext.param.types;

import polyglot.ext.jl.types.*;
import polyglot.types.*;
import polyglot.types.Package;
import polyglot.util.*;
import java.util.*;
import java.io.IOException;

import polyglot.ext.param.Topics;
import polyglot.main.Report;

/**
 * Utility class that performs substitutions on type objects using a
 * map.  Subclasses must define how the substititions are performed and
 * how to cache substituted types.
 */
public class Subst_c implements Subst
{
    /** Map from formal parameters (of type Param) to actuals. */
    protected Map subst;

    /** Cache of types. */
    protected transient Map cache;

    protected transient ParamTypeSystem ts;

    public Subst_c(ParamTypeSystem ts, Map subst, Map cache)
    {
        this.ts = ts;
        this.subst = subst;
        this.cache = new HashMap();
        this.cache.putAll(cache);
    }

    public ParamTypeSystem typeSystem() {
        return ts;
    }

    /**
     * Entries of the underlying substitution map.
     * @return an <code>Iterator</code> of <code>Map.Entry</code>.
     */
    public Iterator entries() {
        return substitutions().entrySet().iterator();
    }

    /**
     * The underlying substitution map.
     */
    public Map substitutions() {
        return Collections.unmodifiableMap(subst);
    }

    /** Perform substitutions on a type, without checking the cache. */
    protected Type uncachedSubstType(Type t) {
        if (t.isArray()) {
            ArrayType at = t.toArray();
            return at.base(substType(at.base()));
        }

        // We may have a parameterized type instantiated on the formals.
        if (t instanceof SubstType) {
            Type tbase = ((SubstType) t).base();
            Map tsubst = ((SubstType) t).subst().substitutions();

            Map newSubst = new HashMap();

            for (Iterator i = tsubst.entrySet().iterator(); i.hasNext(); ) {
                Map.Entry e = (Map.Entry) i.next();
                Object formal = e.getKey();
                Object actual = e.getValue();
                
                Object existent = getSubstValueAsKey(actual);
                if (existent != null) {
                    // In this case:
                    //   this.base is C[T], where T is a formal of C
                    //   t.base is D[U], where U is a formal of D
                    //   t.subst has U -> T, thus t is D[T]
                    //   this.subst has T -> X
                    // so replace U -> T in t.subst with U -> X
                    newSubst.put(formal, existent);
                }
                else {
                    newSubst.put(formal, actual);
                }
            }

            // Now add our substitutions, overriding any substitutions
            // performed in t.subst
            newSubst.putAll(subst);

            // We can use the same cache, since newSubst is compatible with
            // this.subst.
            return ts.subst(tbase, newSubst, cache);
        }

        if (t instanceof ClassType) {
            return substClassType((ClassType) t);
        }

        return t;
    }

    /**
     * When adding a new substitution A-&gt;B to the map, we need to check if 
     * there are already any existing substitutions, say C-&gt;A, and if so,
     * replace them appropriately, in this case with C-&gt;B.
     * 
     * This method allows subclasses to check if a value (B in the 
     * example above) is present as a key. Subclasses may need to override this
     * if the keys and values are not the same object.
     */
    protected Object getSubstValueAsKey(Object v) {
        return substitutions().get(v);
    }
    
    /** Perform substitutions on a class type. Substitutions are performed
     * lazily. */
    public ClassType substClassType(ClassType t) {
        return new SubstClassType_c(ts, t.position(), t, this);
    }

    /** Perform substitutions on a type. */
    public Type substType(Type t) {
        if (t == null || t == this)
            return t;<commit_msg>Generalized the method getSubstValueAsKey to the method substSubstValue, to take care of cases where the subst values are not simply keys (such as in jif, where a formal label parameter may be mapped to the join of two label parameters).<commit_after>package polyglot.ext.param.types;

import java.io.IOException;
import java.util.*;

import polyglot.ext.param.Topics;
import polyglot.main.Report;
import polyglot.types.*;
import polyglot.util.*;

/**
 * Utility class that performs substitutions on type objects using a
 * map.  Subclasses must define how the substititions are performed and
 * how to cache substituted types.
 */
public class Subst_c implements Subst
{
    /** Map from formal parameters (of type Param) to actuals. */
    protected Map subst;

    /** Cache of types. */
    protected transient Map cache;

    protected transient ParamTypeSystem ts;

    public Subst_c(ParamTypeSystem ts, Map subst, Map cache)
    {
        this.ts = ts;
        this.subst = subst;
        this.cache = new HashMap();
        this.cache.putAll(cache);
    }

    public ParamTypeSystem typeSystem() {
        return ts;
    }

    /**
     * Entries of the underlying substitution map.
     * @return an <code>Iterator</code> of <code>Map.Entry</code>.
     */
    public Iterator entries() {
        return substitutions().entrySet().iterator();
    }

    /**
     * The underlying substitution map.
     */
    public Map substitutions() {
        return Collections.unmodifiableMap(subst);
    }

    /** Perform substitutions on a type, without checking the cache. */
    protected Type uncachedSubstType(Type t) {
        if (t.isArray()) {
            ArrayType at = t.toArray();
            return at.base(substType(at.base()));
        }

        // We may have a parameterized type instantiated on the formals.
        if (t instanceof SubstType) {
            Type tbase = ((SubstType) t).base();
            Map tsubst = ((SubstType) t).subst().substitutions();

            Map newSubst = new HashMap();

            for (Iterator i = tsubst.entrySet().iterator(); i.hasNext(); ) {
                Map.Entry e = (Map.Entry) i.next();
                Object formal = e.getKey();
                Object actual = e.getValue();
                
                newSubst.put(formal, substSubstValue(actual));
            }

            // Now add our substitutions, overriding any substitutions
            // performed in t.subst
            newSubst.putAll(subst);

            // We can use the same cache, since newSubst is compatible with
            // this.subst.
            return ts.subst(tbase, newSubst, cache);
        }

        if (t instanceof ClassType) {
            return substClassType((ClassType) t);
        }

        return t;
    }


    /**
     * When adding a new substitution A-&gt;B to the map, we need to check if 
     * there are already any existing substitutions, say C-&gt;A, and if so,
     * replace them appropriately, in this case with C-&gt;B.
     * 
     * This method allows subclasses to perform substitution on a value in
     * the substitution map (B in the 
     * example above). Subclasses may need to override this
     * if the keys and values are not the same object.
     */
    protected Object substSubstValue(Object value) {
        return value;
    }
    
    /** Perform substitutions on a class type. Substitutions are performed
     * lazily. */
    public ClassType substClassType(ClassType t) {
        return new SubstClassType_c(ts, t.position(), t, this);
    }

    /** Perform substitutions on a type. */
    public Type substType(Type t) {
        if (t == null || t == this)
            return t;
{'fraction_non_alphanumeric': 0.09872076495671275, 'fraction_numerical': 0.0, 'mean_word_length': 1.9838087895142638, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4880335', 'n_tokens_mistral': 2210, 'n_tokens_neox': 2102, 'n_words': 737}