public ProjectionErasingJetType(JetType delegate) { this.delegate = delegate; arguments = new ArrayList<TypeProjection>(); for (TypeProjection tp : delegate.getArguments()) { arguments.add(new TypeProjection(Variance.INVARIANT, tp.getType())); } }
// Returns list with type arguments info from supertypes // Example: // - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A> // - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>] // - output[0] = [String, CharSequence], output[1] = [] private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper( @NotNull ClassDescriptor klass, @NotNull Collection<TypeAndVariance> typesFromSuper) { // For each superclass of klass and its parameters, hold their mapping to klass' parameters // #0 of Bar -> A // #1 of Bar -> List<B> // #0 of Baz -> Boolean // #1 of Baz -> A // #0 of Foo -> A (mapped to itself) // #1 of Foo -> B (mapped to itself) Multimap<TypeConstructor, TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap( TypeUtils.makeUnsubstitutedType(klass, JetScope.EMPTY)); // for each parameter of klass, hold arguments in corresponding supertypes List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList(); for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) { parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>()); } // Enumerate all types from super and all its parameters for (TypeAndVariance typeFromSuper : typesFromSuper) { for (TypeParameterDescriptor parameter : typeFromSuper.type.getConstructor().getParameters()) { TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex()); // for given example, this block is executed four times: // 1. typeFromSuper = Bar<String, List<Int>>, parameter = "#0 of Bar", argument = // String // 2. typeFromSuper = Bar<String, List<Int>>, parameter = "#1 of Bar", argument = // List<Int> // 3. typeFromSuper = Baz<Boolean, CharSequence>, parameter = "#0 of Baz", argument = // Boolean // 4. typeFromSuper = Baz<Boolean, CharSequence>, parameter = "#1 of Baz", argument = // CharSequence // if it is mapped to klass' parameter, then store it into map for (TypeProjection projection : substitution.get(parameter.getTypeConstructor())) { // 1. projection = A // 2. projection = List<B> // 3. projection = Boolean // 4. projection = A ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor(); // this condition is true for 1 and 4, false for 2 and 3 if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) { int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex(); Variance effectiveVariance = parameter.getVariance().superpose(typeFromSuper.varianceOfPosition); parameterToArgumentsFromSuper .get(parameterIndex) .add(new TypeProjectionAndVariance(argument, effectiveVariance)); } } } } return parameterToArgumentsFromSuper; }
private void appendTypeProjections( @NotNull List<TypeProjection> typeProjections, @NotNull StringBuilder builder) { for (Iterator<TypeProjection> iterator = typeProjections.iterator(); iterator.hasNext(); ) { TypeProjection typeProjection = iterator.next(); if (typeProjection.getProjectionKind() != Variance.INVARIANT) { builder.append(typeProjection.getProjectionKind()).append(" "); } builder.append(renderType(typeProjection.getType())); if (iterator.hasNext()) { builder.append(", "); } } }
private void appendTypeProjections( StringBuilder result, List<TypeProjection> typeProjections, boolean shortNamesOnly) { for (Iterator<TypeProjection> iterator = typeProjections.iterator(); iterator.hasNext(); ) { TypeProjection typeProjection = iterator.next(); if (typeProjection.getProjectionKind() != Variance.INVARIANT) { result.append(typeProjection.getProjectionKind()).append(" "); } result.append(renderType(typeProjection.getType(), shortNamesOnly)); if (iterator.hasNext()) { result.append(", "); } } }
private Variance calculateArgumentProjectionKindFromSuper( @NotNull TypeProjection argument, @NotNull List<TypeProjectionAndVariance> projectionsFromSuper) { Set<Variance> projectionKindsInSuper = Sets.newLinkedHashSet(); for (TypeProjectionAndVariance projectionAndVariance : projectionsFromSuper) { projectionKindsInSuper.add(projectionAndVariance.typeProjection.getProjectionKind()); } Variance defaultProjectionKind = argument.getProjectionKind(); if (projectionKindsInSuper.size() == 0) { return defaultProjectionKind; } else if (projectionKindsInSuper.size() == 1) { Variance projectionKindInSuper = projectionKindsInSuper.iterator().next(); if (defaultProjectionKind == INVARIANT || defaultProjectionKind == projectionKindInSuper) { return projectionKindInSuper; } else { reportError( "Incompatible projection kinds in type arguments of super methods' return types: " + projectionsFromSuper + ", defined in current: " + argument); return defaultProjectionKind; } } else { reportError( "Incompatible projection kinds in type arguments of super methods' return types: " + projectionsFromSuper); return defaultProjectionKind; } }
public void serialize(@NotNull JetType type) { serialize(type.getConstructor().getDeclarationDescriptor()); if (!type.getArguments().isEmpty()) { sb.append("<"); boolean first = true; for (TypeProjection proj : type.getArguments()) { if (!first) { sb.append(", "); } serialize(proj.getProjectionKind()); serialize(proj.getType()); first = false; } sb.append(">"); } if (type.isNullable()) { sb.append("?"); } }
@NotNull public static JetType createCorrespondingExtensionFunctionType( @NotNull JetType functionType, @NotNull JetType receiverType) { assert KotlinBuiltIns.getInstance().isFunctionType(functionType); List<TypeProjection> typeArguments = functionType.getArguments(); assert !typeArguments.isEmpty(); List<JetType> arguments = Lists.newArrayList(); // excluding the last type argument of the function type, which is the return type int index = 0; int lastIndex = typeArguments.size() - 1; for (TypeProjection typeArgument : typeArguments) { if (index < lastIndex) { arguments.add(typeArgument.getType()); } index++; } JetType returnType = typeArguments.get(lastIndex).getType(); return KotlinBuiltIns.getInstance() .getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType); }
@NotNull private List<TypeProjection> getTypeArgsOfType( @NotNull JetType autoType, @NotNull ClassifierDescriptor classifier, @NotNull List<TypeAndVariance> typesFromSuper) { List<TypeProjection> autoArguments = autoType.getArguments(); if (!(classifier instanceof ClassDescriptor)) { assert autoArguments.isEmpty() : "Unexpected type arguments when type constructor is not ClassDescriptor, type = " + autoType; return autoArguments; } List<List<TypeProjectionAndVariance>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper((ClassDescriptor) classifier, typesFromSuper); // Modify type arguments using info from typesFromSuper List<TypeProjection> resultArguments = Lists.newArrayList(); for (TypeParameterDescriptor parameter : classifier.getTypeConstructor().getParameters()) { TypeProjection argument = autoArguments.get(parameter.getIndex()); JetType argumentType = argument.getType(); List<TypeProjectionAndVariance> projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex()); List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper); JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT); Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper); resultArguments.add(new TypeProjection(projectionKind, type)); } return resultArguments; }
/** * Determines what constraint (supertype, subtype or equal) should be generated for type parameter * {@code T} in a constraint like (in this example subtype one): <br> * {@code MyClass<in/out/- A> <: MyClass<in/out/- B>}, where {@code MyClass<in/out/- T>} is * declared. <br> * The parameters description is given according to the example above. * * @param typeParameterVariance declared variance of T * @param subjectTypeProjection {@code in/out/- A} * @param constrainingTypeProjection {@code in/out/- B} * @param upperConstraintKind kind of the constraint {@code MyClass<...A> <: MyClass<...B>} * (subtype in this example). * @return kind of constraint to be generated: {@code A <: B} (subtype), {@code A >: B} * (supertype) or {@code A = B} (equal). */ @NotNull private static ConstraintKind getTypeParameterConstraintKind( @NotNull Variance typeParameterVariance, @NotNull TypeProjection subjectTypeProjection, @NotNull TypeProjection constrainingTypeProjection, @NotNull ConstraintKind upperConstraintKind) { // If variance of type parameter is non-trivial, it should be taken into consideration to infer // result constraint type. // Otherwise when type parameter declared as INVARIANT, there might be non-trivial use-site // variance of a supertype. // // Example: Let class MyClass<T> is declared. // // If super type has 'out' projection: // MyClass<A> <: MyClass<out B>, // then constraint A <: B can be generated. // // If super type has 'in' projection: // MyClass<A> <: MyClass<in B>, // then constraint A >: B can be generated. // // Otherwise constraint A = B should be generated. Variance varianceForTypeParameter; if (typeParameterVariance != INVARIANT) { varianceForTypeParameter = typeParameterVariance; } else if (upperConstraintKind == SUPER_TYPE) { varianceForTypeParameter = constrainingTypeProjection.getProjectionKind(); } else if (upperConstraintKind == SUB_TYPE) { varianceForTypeParameter = subjectTypeProjection.getProjectionKind(); } else { varianceForTypeParameter = INVARIANT; } return getTypeParameterConstraintKind(varianceForTypeParameter, upperConstraintKind); }
public String toString() { return typeProjection.toString(); }
private void addConstraint( @NotNull ConstraintKind constraintKind, @NotNull JetType subjectType, @Nullable JetType constrainingType, @NotNull ConstraintPosition constraintPosition) { if (constrainingType == TypeUtils.NO_EXPECTED_TYPE || constrainingType == DONT_CARE || constrainingType == CANT_INFER) { return; } if (constrainingType == null || (ErrorUtils.isErrorType(constrainingType) && constrainingType != PLACEHOLDER_FUNCTION_TYPE)) { hasErrorInConstrainingTypes = true; return; } assert subjectType != TypeUtils.NO_EXPECTED_TYPE : "Subject type shouldn't be NO_EXPECTED_TYPE (in position " + constraintPosition + " )"; if (ErrorUtils.isErrorType(subjectType)) return; DeclarationDescriptor subjectTypeDescriptor = subjectType.getConstructor().getDeclarationDescriptor(); KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance(); if (constrainingType == PLACEHOLDER_FUNCTION_TYPE) { if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(subjectType)) { if (subjectTypeDescriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(subjectTypeDescriptor) != null) { // a constraint binds type parameter and any function type, so there is no new info and no // error return; } errorConstraintPositions.add(constraintPosition); } return; } // todo temporary hack // function literal without declaring receiver type { x -> ... } // can be considered as extension function if one is expected // (special type constructor for function/ extension function should be introduced like // PLACEHOLDER_FUNCTION_TYPE) if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(constrainingType) && kotlinBuiltIns.isExtensionFunctionType(subjectType)) { constrainingType = createCorrespondingExtensionFunctionType(constrainingType, DONT_CARE); } DeclarationDescriptor constrainingTypeDescriptor = constrainingType.getConstructor().getDeclarationDescriptor(); if (subjectTypeDescriptor instanceof TypeParameterDescriptor) { TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) subjectTypeDescriptor; TypeConstraintsImpl typeConstraints = typeParameterConstraints.get(typeParameter); if (typeConstraints != null) { if (TypeUtils.dependsOnTypeParameterConstructors( constrainingType, Collections.singleton(DONT_CARE.getConstructor()))) { return; } if (subjectType.isNullable() && constrainingType.isNullable()) { constrainingType = TypeUtils.makeNotNullable(constrainingType); } typeConstraints.addBound(constraintKind, constrainingType); return; } } if (constrainingTypeDescriptor instanceof TypeParameterDescriptor) { assert typeParameterConstraints.get(constrainingTypeDescriptor) == null : "Constraining type contains type variable " + constrainingTypeDescriptor.getName(); } if (constraintKind == SUB_TYPE && kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) { // following constraints are always true: // 'Nothing' is a subtype of any type if (!constrainingType.isNullable()) return; // 'Nothing?' is a subtype of nullable type if (subjectType.isNullable()) return; } if (!(constrainingTypeDescriptor instanceof ClassDescriptor) || !(subjectTypeDescriptor instanceof ClassDescriptor)) { errorConstraintPositions.add(constraintPosition); return; } switch (constraintKind) { case SUB_TYPE: { if (kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) break; JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(constrainingType, subjectType); if (correspondingSupertype != null) { constrainingType = correspondingSupertype; } break; } case SUPER_TYPE: { if (kotlinBuiltIns.isNothingOrNullableNothing(subjectType)) break; JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(subjectType, constrainingType); if (correspondingSupertype != null) { subjectType = correspondingSupertype; } } case EQUAL: // nothing } if (constrainingType.getConstructor() != subjectType.getConstructor()) { errorConstraintPositions.add(constraintPosition); return; } TypeConstructor typeConstructor = subjectType.getConstructor(); List<TypeProjection> subjectArguments = subjectType.getArguments(); List<TypeProjection> constrainingArguments = constrainingType.getArguments(); List<TypeParameterDescriptor> parameters = typeConstructor.getParameters(); for (int i = 0; i < subjectArguments.size(); i++) { Variance typeParameterVariance = parameters.get(i).getVariance(); TypeProjection subjectArgument = subjectArguments.get(i); TypeProjection constrainingArgument = constrainingArguments.get(i); ConstraintKind typeParameterConstraintKind = getTypeParameterConstraintKind( typeParameterVariance, subjectArgument, constrainingArgument, constraintKind); addConstraint( typeParameterConstraintKind, subjectArgument.getType(), constrainingArgument.getType(), constraintPosition); } }