compile.type.TypeVar.java Source code

Java tutorial

Introduction

Here is the source code for compile.type.TypeVar.java

Source

/**
 * ADOBE SYSTEMS INCORPORATED
 * Copyright 2009-2013 Adobe Systems Incorporated
 * All Rights Reserved.
 *
 * NOTICE: Adobe permits you to use, modify, and distribute
 * this file in accordance with the terms of the MIT license,
 * a copy of which can be found in the LICENSE.txt file or at
 * http://opensource.org/licenses/MIT.
 */
package compile.type;

import com.google.common.collect.Sets;
import compile.Loc;
import compile.Pair;
import compile.Session;
import compile.type.constraint.Constraint;
import compile.type.constraint.SubsumptionConstraint;
import compile.type.kind.Kind;
import compile.type.visit.EquivState;
import compile.type.visit.SubstMap;
import compile.type.visit.TypeParamCollector;
import compile.type.visit.TypeVisitor;

import java.util.HashSet;
import java.util.Set;

/**
 * Type variable.
 *
 * @author Basil Hosmer
 */
public final class TypeVar extends NonScopeType {
    private final String name;
    private final Kind kind;
    private Constraint constraint;
    private TypeParam sourceParam;
    private Set<TypeParam> unifiedParams;

    private TypeVar(final Loc loc, final String name, final Kind kind, final Constraint constraint,
            final TypeParam sourceParam) {
        super(loc);
        this.name = name;
        this.kind = kind;
        this.constraint = constraint;
        this.sourceParam = sourceParam;
        this.unifiedParams = Sets.newIdentityHashSet();

        if (sourceParam != null)
            unifiedParams.add(sourceParam);

        if (kind == null)
            assert false : "null kind in TypeVar ctor: " + name;

        if (constraint == null)
            assert false : "null constraint in TypeVar ctor: " + name;
    }

    public TypeVar(final Loc loc, final String name, final Kind kind, final Constraint constraint) {
        this(loc, name, kind, constraint, null);
    }

    /**
     * Note that param constraint is installed here
     * without modification--must be replaced by
     * instantiation after construction.
     */
    public TypeVar(final String name, final TypeParam sourceParam) {
        this(sourceParam.getLoc(), name, sourceParam.getKind(), sourceParam.getConstraint(), sourceParam);
    }

    public String getName() {
        return name;
    }

    public Constraint getConstraint() {
        return constraint;
    }

    public void setConstraint(final Constraint constraint) {
        this.constraint = constraint;
    }

    public boolean hasSourceParam() {
        return sourceParam != null;
    }

    public TypeParam getSourceParam() {
        return sourceParam;
    }

    public Set<TypeParam> getUnifiedParams() {
        return unifiedParams;
    }

    public void addUnifiedParam(final TypeParam param) {
        this.unifiedParams.add(param);
    }

    public void addUnifiedParams(final Set<TypeParam> params) {
        this.unifiedParams.addAll(params);
    }

    public TypeParam getBackingParam(final Set<String> exclude, final ScopeType scope) {
        if (sourceParam != null && !exclude.contains(sourceParam.getName())
                && (scope.getLoc().equals(sourceParam.getTypeScope().getLoc()))) {
            if (Session.isDebug())
                Session.debug(loc, "type var {0}: in-scope source param {1} available, using", name,
                        sourceParam.dump());

            return sourceParam;
        }

        // next best is a unified param from the original scope
        if (!unifiedParams.isEmpty()) {
            for (final TypeParam unified : unifiedParams) {
                if (!exclude.contains(unified.getName())
                        && (scope.getLoc().equals(unified.getTypeScope().getLoc()))) {
                    if (Session.isDebug())
                        Session.debug(loc, "type var {0}: in-scope unified param {1} available, using", name,
                                unified.dump());

                    return unified;
                }
            }
        }

        return null;
    }

    // Type

    public Kind getKind() {
        return kind;
    }

    /**
     * quantify this singleton type var.
     *
     * Note: per the "types don't come from nowhere" rule, there should
     * be no legitimate cases where a lone type variable is quantified.
     */
    public Type quantify(final SubstMap newParams, final SubstMap ambientParams) {
        final Type applied = subst(ambientParams.compose(loc, newParams));

        // add new params to our result type
        for (final Type type : newParams.values())
            applied.addParam((TypeParam) type);

        return applied;

        /*
        if (newParams.containsKey(this))
        {
        // see header comment
        // Session.error(loc, "quantifying lone type var {0}", dump());
            
        final TypeParam param = (TypeParam)newParams.get(this);
        final TypeRef typeRef = new TypeRef(loc, param);
        typeRef.addParam(param);
        return typeRef;
        }
            
        // normal case
        return ambientParams.containsKey(this) ?
        new TypeRef(loc, (TypeParam)ambientParams.get(this)) :
        this;
        */
    }

    /**
     * build a param map for this singleton type var.
     *
     * Note: per the "types don't come from nowhere" rule, there should
     * be no legitimate cases where a param map is built for a lone type variable.
     */
    public SubstMap buildParamMap(final Set<TypeVar> vars, final int nameGenOffset, final TypeEnv env) {
        final Set<TypeVar> qvars = Sets.intersection(vars, getVars());

        if (qvars.isEmpty())
            return SubstMap.EMPTY;

        // when generating param names, avoid names of used params.
        final Set<String> usedNames = new HashSet<String>();

        for (final TypeParam param : TypeParamCollector.collect(this))
            usedNames.add(param.getName());

        // begin generating names from this offset into the generated name space.
        int genIndex = nameGenOffset;

        final SubstMap substMap = new SubstMap();

        for (final TypeVar v : qvars) {
            final String name;

            // broken
            //            final TypeParam param = v.getBackingParam(usedNames, this);
            //            if (param != null)
            //            {
            //                name = param.getName();
            //            }
            //            else
            {
                String tmp;
                do {
                    tmp = nameGen(genIndex++);
                } while (usedNames.contains(tmp));

                name = tmp;
            }

            usedNames.add(name);

            // NOTE: v's constraint is ignored here, because it needs to be
            // not just transferred to the corresponding param, but also run
            // through this same substitution map at quantification time.
            // Users of this map are responsible for doing this.
            //
            substMap.put(v, new TypeParam(v.getLoc(), name, v.getKind(), null));
        }

        return substMap;

        /*
        if (vars.contains(this))
        {
        Session.error(loc, "building param map for lone type var {0}", dump());
            
        final TypeParam param = hasSourceParam() ?
            getSourceParam() : new TypeParam(loc, name, kind, constraint);
            
        final SubstMap subst = SubstMap.bindVar(loc, this, param, env);
            
        if (subst == null)
        {
            Session.error(loc, "internal error: failed to bind var {0} to param {1}",
                dump(), param.dump());
            
            return SubstMap.EMPTY;
        }
            
        return subst;
        }
            
        // normal case
        return SubstMap.EMPTY;
        */
    }

    public SubstMap unify(final Loc loc, Type other, final TypeEnv env) {
        other = other.deref();

        return kind.equals(other.getKind()) ? SubstMap.bindVar(loc, this, other, env) : null;
    }

    public SubstMap subsume(final Loc loc, final Type type, final TypeEnv env) {
        if (type instanceof TypeVar) {
            final TypeVar var = (TypeVar) type;

            final Pair<? extends Constraint, SubstMap> merged = constraint.merge(var.constraint, env);

            if (merged == null)
                return null;

            setConstraint(merged.left);

            return merged.right;
        } else {
            final Pair<? extends Constraint, SubstMap> merged = constraint.merge(new SubsumptionConstraint(type),
                    env);

            if (merged == null)
                return null;

            setConstraint(merged.left);

            return merged.right;
        }
    }

    public boolean equiv(final Type other, final EquivState state) {
        assert false : "TypeVar.equiv()";
        return false;
    }

    public <T> T accept(final TypeVisitor<T> visitor) {
        return visitor.visit(this);
    }

    // Object

    @Override
    public boolean equals(final Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        final TypeVar typeVar = (TypeVar) o;

        if (!name.equals(typeVar.name))
            return false;
        if (!kind.equals(typeVar.kind))
            return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + kind.hashCode();
        return result;
    }
}