001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.types.expressions;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
022    import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
023    import org.jetbrains.kotlin.psi.KtTypeReference;
024    import org.jetbrains.kotlin.resolve.BindingContext;
025    import org.jetbrains.kotlin.resolve.BindingTrace;
026    import org.jetbrains.kotlin.resolve.PossiblyBareType;
027    import org.jetbrains.kotlin.types.ErrorUtils;
028    import org.jetbrains.kotlin.types.KotlinType;
029    import org.jetbrains.kotlin.types.TypeConstructor;
030    import org.jetbrains.kotlin.types.TypeReconstructionResult;
031    
032    import static org.jetbrains.kotlin.diagnostics.Errors.NO_TYPE_ARGUMENTS_ON_RHS;
033    
034    public class TypeReconstructionUtil {
035        @NotNull
036        public static KotlinType reconstructBareType(
037                @NotNull KtTypeReference right,
038                @NotNull PossiblyBareType possiblyBareTarget,
039                @Nullable KotlinType subjectType,
040                @NotNull BindingTrace trace,
041                @NotNull KotlinBuiltIns builtIns
042        ) {
043            if (subjectType == null) {
044                // Recovery: let's reconstruct as if we were casting from Any, to get some type there
045                subjectType = builtIns.getAnyType();
046            }
047            TypeReconstructionResult reconstructionResult = possiblyBareTarget.reconstruct(subjectType);
048            if (!reconstructionResult.isAllArgumentsInferred()) {
049                TypeConstructor typeConstructor = possiblyBareTarget.getBareTypeConstructor();
050                trace.report(NO_TYPE_ARGUMENTS_ON_RHS.on(right,
051                                                         typeConstructor.getParameters().size(),
052                                                         allStarProjectionsString(typeConstructor)));
053            }
054    
055            KotlinType targetType = reconstructionResult.getResultingType();
056            if (targetType != null) {
057                if (possiblyBareTarget.isBare()) {
058                    trace.record(BindingContext.TYPE, right, targetType);
059                }
060                return targetType;
061            }
062    
063            return ErrorUtils.createErrorType("Failed to reconstruct type: " + right.getText());
064        }
065    
066        @NotNull
067        private static String allStarProjectionsString(@NotNull TypeConstructor constructor) {
068            int size = constructor.getParameters().size();
069            assert size != 0 : "No projections possible for a nilary type constructor" + constructor;
070            ClassifierDescriptor declarationDescriptor = constructor.getDeclarationDescriptor();
071            assert declarationDescriptor != null : "No declaration descriptor for type constructor " + constructor;
072            String name = declarationDescriptor.getName().asString();
073    
074            return getTypeNameAndStarProjectionsString(name, size);
075        }
076    
077        @NotNull
078        public static String getTypeNameAndStarProjectionsString(@NotNull String name, int size) {
079            StringBuilder builder = new StringBuilder(name);
080            builder.append("<");
081            for (int i = 0; i < size; i++) {
082                builder.append("*");
083                if (i == size - 1) break;
084                builder.append(", ");
085            }
086            builder.append(">");
087    
088            return builder.toString();
089        }
090    }