TypeSubstitutor.java 3.7 KB
Newer Older
A
Andrey Breslav 已提交
1 2 3 4
package org.jetbrains.jet.lang.types;

import org.jetbrains.annotations.NotNull;

5
import java.util.*;
A
Andrey Breslav 已提交
6 7 8 9 10 11 12 13 14

/**
 * @author abreslav
 */
public class TypeSubstitutor {
    public static final TypeSubstitutor INSTANCE = new TypeSubstitutor();

    private TypeSubstitutor() {}

A
Andrey Breslav 已提交
15
    public JetType substitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
A
Andrey Breslav 已提交
16 17 18 19
        return substitute(getSubstitutionContext(context), subject, howThisTypeIsUsed);
    }

    @NotNull
A
Andrey Breslav 已提交
20
    public JetType substitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
A
Andrey Breslav 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33
        TypeProjection value = substitutionContext.get(type.getConstructor());
        if (value != null) {
            Variance projectionKind = value.getProjectionKind();
            if (howThisTypeIsUsed.allowsInPosition() && !projectionKind.allowsInPosition()
                    || howThisTypeIsUsed.allowsOutPosition() && !projectionKind.allowsOutPosition()) {
                return ErrorType.createWrongVarianceErrorType(value);
            }
            return value.getType();
        }

        return specializeType(type, substituteInArguments(substitutionContext, type));
    }

A
Andrey Breslav 已提交
34
    public Map<TypeConstructor, TypeProjection> getSubstitutionContext(JetType context) {
A
Andrey Breslav 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
        List<TypeParameterDescriptor> parameters = context.getConstructor().getParameters();
        List<TypeProjection> contextArguments = context.getArguments();

        return buildSubstitutionContext(parameters, contextArguments);
    }

    public Map<TypeConstructor, TypeProjection> buildSubstitutionContext(List<TypeParameterDescriptor> parameters, List<TypeProjection> contextArguments) {
        Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>();
        for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
            TypeParameterDescriptor parameter = parameters.get(i);
            TypeProjection value = contextArguments.get(i);
            parameterValues.put(parameter.getTypeConstructor(), value);
        }
        return parameterValues;
    }

    @NotNull
    private TypeProjection substituteInProjection(Map<TypeConstructor, TypeProjection> parameterValues, TypeProjection subject) {
A
Andrey Breslav 已提交
53
        @NotNull JetType subjectType = subject.getType();
A
Andrey Breslav 已提交
54 55 56 57 58 59 60 61
        TypeProjection value = parameterValues.get(subjectType.getConstructor());
        if (value != null) {
            return value;
        }
        List<TypeProjection> newArguments = substituteInArguments(parameterValues, subjectType);
        return new TypeProjection(subject.getProjectionKind(), specializeType(subjectType, newArguments));
    }

A
Andrey Breslav 已提交
62
    private List<TypeProjection> substituteInArguments(Map<TypeConstructor, TypeProjection> parameterValues, JetType subjectType) {
A
Andrey Breslav 已提交
63 64 65 66 67 68 69
        List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
        for (TypeProjection argument : subjectType.getArguments()) {
            newArguments.add(substituteInProjection(parameterValues, argument));
        }
        return newArguments;
    }

A
Andrey Breslav 已提交
70 71
    private JetType specializeType(JetType type, List<TypeProjection> newArguments) {
        return new JetTypeImpl(type.getAttributes(), type.getConstructor(), type.isNullable(), newArguments, type.getMemberScope());
A
Andrey Breslav 已提交
72
    }
73

A
Andrey Breslav 已提交
74 75 76
    public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) {
        Set<JetType> result = new HashSet<JetType>();
        for (JetType type : types) {
77 78 79 80
            result.add(substitute(substitutionContext, type, howTheseTypesWillBeUsed));
        }
        return result;
    }
A
Andrey Breslav 已提交
81
}