TypeSubstitutor.java 7.6 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 22 23
    public static final TypeSubstitutor INSTANCE = new TypeSubstitutor();

    private TypeSubstitutor() {}

24 25
    public JetType safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
        return safeSubstitute(TypeUtils.buildSubstitutionContext(context), subject, howThisTypeIsUsed);
A
Andrey Breslav 已提交
26 27 28
    }

    @NotNull
29 30 31 32
    public JetType safeSubstitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
        try {
            return unsafeSubstitute(substitutionContext, type, howThisTypeIsUsed);
        } catch (SubstitutionException e) {
A
rename  
Andrey Breslav 已提交
33
            return ErrorUtils.createErrorType(e.getMessage());
34 35 36 37
        }
    }

    @Nullable
A
Andrey Breslav 已提交
38
    public JetType substitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
39 40 41 42 43 44 45 46 47 48 49
        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 已提交
50
        if (value != null) {
51 52
            assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;

53 54 55 56 57 58
            return substitutionResult(substitutionContext, (TypeParameterDescriptor) constructor.getDeclarationDescriptor(), howThisTypeIsUsed, Variance.INVARIANT, value).getType();
//
//            if (!allows(howThisTypeIsUsed, value.getProjectionKind())) {
//                throw new SubstitutionException("!!" + value.toString());
//            }
//            return value.getType();
A
Andrey Breslav 已提交
59 60
        }

61
        return specializeType(type, substitutionContext, howThisTypeIsUsed);
A
Andrey Breslav 已提交
62 63
    }

64 65 66 67 68 69 70 71 72 73 74 75
    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));
        }
76 77 78 79
        return new JetTypeImpl(
                subjectType.getAttributes(),
                subjectType.getConstructor(),
                subjectType.isNullable(),
80
                newArguments,
81
                new SubstitutingScope(subjectType.getMemberScope(), substitutionContext));
A
Andrey Breslav 已提交
82 83
    }

84 85 86
    @NotNull
    private TypeProjection substituteInProjection(
            @NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
87 88 89 90 91 92
            @NotNull TypeProjection passedProjection,
            @NotNull TypeParameterDescriptor correspondingTypeParameter,
            @NotNull Variance contextCallSiteVariance) throws SubstitutionException {
        JetType typeToSubstituteIn = passedProjection.getType();
        Variance passedProjectionKind = passedProjection.getProjectionKind();
        Variance parameterVariance = correspondingTypeParameter.getVariance();
93

94
        Variance effectiveProjectionKind = asymmetricOr(passedProjectionKind, parameterVariance);
95
        Variance effectiveContextVariance = contextCallSiteVariance.superpose(effectiveProjectionKind);
96

97 98 99
        TypeProjection projectionValue = substitutionContext.get(typeToSubstituteIn.getConstructor());
        if (projectionValue != null) {
            assert typeToSubstituteIn.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;
100

101
            if (!allows(parameterVariance, passedProjectionKind)) {
102
                return TypeUtils.makeStarProjection(correspondingTypeParameter);
103 104
            }

105
            return substitutionResult(substitutionContext, correspondingTypeParameter, effectiveContextVariance, passedProjectionKind, projectionValue);
A
Andrey Breslav 已提交
106
        }
107
        return new TypeProjection(
108 109 110 111 112
                passedProjectionKind,
                specializeType(
                        typeToSubstituteIn,
                        substitutionContext,
                        effectiveContextVariance));
A
Andrey Breslav 已提交
113
    }
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
    private TypeProjection substitutionResult(
            Map<TypeConstructor, TypeProjection> substitutionContext,
            TypeParameterDescriptor correspondingTypeParameter,
            Variance effectiveContextVariance,
            Variance passedProjectionKind,
            TypeProjection value) throws SubstitutionException {
        Variance projectionKindValue = value.getProjectionKind();
        JetType typeValue = value.getType();
        Variance effectiveProjectionKindValue = asymmetricOr(passedProjectionKind, projectionKindValue);
        JetType effectiveTypeValue;
        switch (effectiveContextVariance) {
            case INVARIANT:
                effectiveProjectionKindValue = projectionKindValue;
                effectiveTypeValue = typeValue;
                break;
            case IN_VARIANCE:
                if (projectionKindValue == Variance.OUT_VARIANCE) {
                    throw new SubstitutionException(""); // TODO
//                    effectiveProjectionKindValue = Variance.INVARIANT;
//                    effectiveTypeValue = JetStandardClasses.getNothingType();
                }
                else {
                    effectiveTypeValue = typeValue;
                }
                break;
            case OUT_VARIANCE:
                if (projectionKindValue == Variance.IN_VARIANCE) {
                    effectiveProjectionKindValue = Variance.INVARIANT;
                    effectiveTypeValue = correspondingTypeParameter.getBoundsAsType();
                }
                else {
                    effectiveTypeValue = typeValue;
                }
                break;
            default:
                throw new IllegalStateException(effectiveContextVariance.toString());
        }

//            if (!allows(effectiveContextVariance, projectionKindValue)) {
//                throw new SubstitutionException(""); // TODO : error message
//            }
//
        return new TypeProjection(effectiveProjectionKindValue,  specializeType(effectiveTypeValue, substitutionContext, effectiveContextVariance));
    }

160 161 162
    private static Variance asymmetricOr(Variance a, Variance b) {
        return a == Variance.INVARIANT ? b : a;
    }
163

164
    private static boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
165 166 167 168
        switch (declarationSiteVariance) {
            case INVARIANT: return true;
            case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE;
            case OUT_VARIANCE: return callSiteVariance != Variance.IN_VARIANCE;
169
        }
170
        throw new IllegalStateException(declarationSiteVariance.toString());
171
    }
A
Andrey Breslav 已提交
172
}