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

import org.jetbrains.annotations.NotNull;
4
import org.jetbrains.annotations.Nullable;
5
import org.jetbrains.jet.lang.resolve.SubstitutingScope;
A
Andrey Breslav 已提交
6

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

/**
 * @author abreslav
 */
public class TypeSubstitutor {
13 14 15 16 17 18 19

    public static final class SubstitutionException extends Exception {
        public SubstitutionException(String message) {
            super(message);
        }
    }

A
Andrey Breslav 已提交
20 21
    public static final TypeSubstitutor INSTANCE = new TypeSubstitutor();

22 23 24 25 26 27 28
    public static final TypeSubstitutor INSTANCE_FOR_CONSTRUCTORS = new TypeSubstitutor() {
        @Override
        protected boolean errorCondition(Variance ve, Variance p1) {
            return false;
        }
    };

A
Andrey Breslav 已提交
29 30
    private TypeSubstitutor() {}

31 32
    public JetType safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
        return safeSubstitute(TypeUtils.buildSubstitutionContext(context), subject, howThisTypeIsUsed);
A
Andrey Breslav 已提交
33 34 35
    }

    @NotNull
36 37 38 39 40 41 42 43 44
    public JetType safeSubstitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
        try {
            return unsafeSubstitute(substitutionContext, type, howThisTypeIsUsed);
        } catch (SubstitutionException e) {
            return ErrorType.createErrorType(e.getMessage());
        }
    }

    @Nullable
A
Andrey Breslav 已提交
45
    public JetType substitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
46 47 48 49 50 51 52 53 54 55 56
        try {
            return unsafeSubstitute(substitutionContext, type, howThisTypeIsUsed);
        } catch (SubstitutionException e) {
            return null;
        }
    }

    @NotNull
    private JetType unsafeSubstitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) throws SubstitutionException {
        TypeConstructor constructor = type.getConstructor();
        TypeProjection value = substitutionContext.get(constructor);
A
Andrey Breslav 已提交
57
        if (value != null) {
58 59 60 61
            assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;

            if (errorCondition(howThisTypeIsUsed, value.getProjectionKind())) {
                throw new SubstitutionException("!!" + value.toString());
A
Andrey Breslav 已提交
62 63 64 65
            }
            return value.getType();
        }

66
        return specializeType(type, substitutionContext, howThisTypeIsUsed);
A
Andrey Breslav 已提交
67 68
    }

69 70 71 72 73 74 75 76 77 78 79 80
    private JetType specializeType(JetType subjectType, Map<TypeConstructor, TypeProjection> substitutionContext, Variance callSiteVariance) throws SubstitutionException {
        List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
        List<TypeProjection> arguments = subjectType.getArguments();
        for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) {
            TypeProjection argument = arguments.get(i);
            TypeParameterDescriptor parameterDescriptor = subjectType.getConstructor().getParameters().get(i);
            newArguments.add(substituteInProjection(
                    substitutionContext,
                    argument,
                    parameterDescriptor,
                    callSiteVariance));
        }
81 82 83 84
        return new JetTypeImpl(
                subjectType.getAttributes(),
                subjectType.getConstructor(),
                subjectType.isNullable(),
85
                newArguments,
86
                new SubstitutingScope(subjectType.getMemberScope(), substitutionContext));
A
Andrey Breslav 已提交
87 88
    }

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    @NotNull
    private TypeProjection substituteInProjection(
            @NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
            @NotNull TypeProjection p0_E,
            @NotNull TypeParameterDescriptor d_T, // variance of the parameter this projection is substituted for
            @NotNull Variance v) throws SubstitutionException {
        JetType E = p0_E.getType();
        Variance p0 = p0_E.getProjectionKind();
        Variance d = d_T.getVariance();

        Variance p01 = (p0 == Variance.INVARIANT) ? d : p0;
        Variance ve = v.superpose(p01);

        TypeProjection p1_A = substitutionContext.get(E.getConstructor());
        if (p1_A != null) {
            assert E.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;

            JetType A = p1_A.getType();
            Variance p1 = p1_A.getProjectionKind();

            if (!allows(d, p0)) {
                return TypeUtils.makeStarProjection(d_T);
            }

            if (errorCondition(ve, p1)) {
                throw new SubstitutionException(""); // TODO : error message
            }

            return new TypeProjection(p0 == Variance.INVARIANT ? p1 : p0,  specializeType(A, substitutionContext, ve));
A
Andrey Breslav 已提交
118
        }
119 120 121
        return new TypeProjection(
                p0,
                specializeType(E, substitutionContext, ve));
A
Andrey Breslav 已提交
122 123
    }

124 125
    protected boolean errorCondition(Variance ve, Variance p1) {
        return !allows(ve, p1);
A
Andrey Breslav 已提交
126
    }
127

A
Andrey Breslav 已提交
128 129 130
    public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) {
        Set<JetType> result = new HashSet<JetType>();
        for (JetType type : types) {
131
            result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
132 133 134
        }
        return result;
    }
135

136 137 138 139 140
    private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
        switch (declarationSiteVariance) {
            case INVARIANT: return true;
            case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE;
            case OUT_VARIANCE: return callSiteVariance != Variance.IN_VARIANCE;
141
        }
142
        throw new IllegalStateException(declarationSiteVariance.toString());
143
    }
A
Andrey Breslav 已提交
144
}