001    /*
002     * Copyright 2010-2013 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.jet.lang.resolve;
018    
019    import com.intellij.psi.util.PsiTreeUtil;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
024    import org.jetbrains.jet.lang.psi.*;
025    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
026    import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter;
027    import org.jetbrains.jet.lang.types.*;
028    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
029    import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue;
030    
031    import javax.inject.Inject;
032    import java.util.ArrayList;
033    import java.util.Collection;
034    import java.util.Collections;
035    import java.util.List;
036    
037    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
038    import static org.jetbrains.jet.lang.types.Variance.*;
039    
040    public class TypeResolver {
041    
042        private AnnotationResolver annotationResolver;
043        private DescriptorResolver descriptorResolver;
044        private QualifiedExpressionResolver qualifiedExpressionResolver;
045        private ModuleDescriptor moduleDescriptor;
046    
047        @Inject
048        public void setDescriptorResolver(DescriptorResolver descriptorResolver) {
049            this.descriptorResolver = descriptorResolver;
050        }
051    
052        @Inject
053        public void setAnnotationResolver(AnnotationResolver annotationResolver) {
054            this.annotationResolver = annotationResolver;
055        }
056    
057        @Inject
058        public void setQualifiedExpressionResolver(QualifiedExpressionResolver qualifiedExpressionResolver) {
059            this.qualifiedExpressionResolver = qualifiedExpressionResolver;
060        }
061    
062        @Inject
063        public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
064            this.moduleDescriptor = moduleDescriptor;
065        }
066    
067        @NotNull
068        public JetType resolveType(@NotNull JetScope scope, @NotNull JetTypeReference typeReference, BindingTrace trace, boolean checkBounds) {
069            JetType cachedType = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
070            if (cachedType != null) return cachedType;
071    
072            List<AnnotationDescriptor> annotations = annotationResolver.getResolvedAnnotations(typeReference.getAnnotations(), trace);
073    
074            JetTypeElement typeElement = typeReference.getTypeElement();
075            JetType type = resolveTypeElement(scope, annotations, typeElement, trace, checkBounds);
076            trace.record(BindingContext.TYPE, typeReference, type);
077            trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, scope);
078    
079            return type;
080        }
081    
082        @NotNull
083        private JetType resolveTypeElement(final JetScope scope, final List<AnnotationDescriptor> annotations,
084                JetTypeElement typeElement, final BindingTrace trace, final boolean checkBounds) {
085    
086            final JetType[] result = new JetType[1];
087            if (typeElement != null) {
088                typeElement.accept(new JetVisitorVoid() {
089                    @Override
090                    public void visitUserType(JetUserType type) {
091                        JetSimpleNameExpression referenceExpression = type.getReferenceExpression();
092                        String referencedName = type.getReferencedName();
093                        if (referenceExpression == null || referencedName == null) {
094                            return;
095                        }
096    
097                        ClassifierDescriptor classifierDescriptor = resolveClass(scope, type, trace);
098                        if (classifierDescriptor == null) {
099                            resolveTypeProjections(scope, ErrorUtils.createErrorType("No type").getConstructor(), type.getTypeArguments(), trace, checkBounds);
100                            return;
101                        }
102    
103                        trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, classifierDescriptor);
104    
105                        if (classifierDescriptor instanceof TypeParameterDescriptor) {
106                            TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) classifierDescriptor;
107    
108                            JetScope scopeForTypeParameter = getScopeForTypeParameter(typeParameterDescriptor, checkBounds);
109                            if (scopeForTypeParameter instanceof ErrorUtils.ErrorScope) {
110                                result[0] = ErrorUtils.createErrorType("?");
111                            }
112                            else {
113                                result[0] = new JetTypeImpl(
114                                        annotations,
115                                        typeParameterDescriptor.getTypeConstructor(),
116                                        TypeUtils.hasNullableLowerBound(typeParameterDescriptor),
117                                        Collections.<TypeProjection>emptyList(),
118                                        scopeForTypeParameter
119                                );
120                            }
121    
122                            resolveTypeProjections(scope, ErrorUtils.createErrorType("No type").getConstructor(), type.getTypeArguments(), trace, checkBounds);
123    
124                            DeclarationDescriptor containing = typeParameterDescriptor.getContainingDeclaration();
125                            if (containing instanceof ClassDescriptor) {
126                                // Type parameter can't be inherited from member of parent class, so we can skip subclass check
127                                DescriptorResolver.checkHasOuterClassInstance(scope, trace, referenceExpression, (ClassDescriptor) containing, false);
128                            }
129                        }
130                        else if (classifierDescriptor instanceof ClassDescriptor) {
131                            ClassDescriptor classDescriptor = (ClassDescriptor) classifierDescriptor;
132    
133                            TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor();
134                            List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments(), trace, checkBounds);
135                            List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
136                            int expectedArgumentCount = parameters.size();
137                            int actualArgumentCount = arguments.size();
138                            if (ErrorUtils.isError(typeConstructor)) {
139                                result[0] = ErrorUtils.createErrorType("[Error type: " + typeConstructor + "]");
140                            }
141                            else {
142                                if (actualArgumentCount != expectedArgumentCount) {
143                                    if (actualArgumentCount == 0) {
144                                        if (rhsOfIsExpression(type) || rhsOfIsPattern(type)) {
145                                            trace.report(NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION.on(type, expectedArgumentCount, allStarProjectionsString(typeConstructor)));
146                                        }
147                                        else {
148                                            trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type, expectedArgumentCount));
149                                        }
150                                    }
151                                    else {
152                                        trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type.getTypeArgumentList(), expectedArgumentCount));
153                                    }
154                                }
155                                else {
156                                    result[0] = new JetTypeImpl(
157                                            annotations,
158                                            typeConstructor,
159                                            false,
160                                            arguments,
161                                            classDescriptor.getMemberScope(arguments)
162                                    );
163                                    if (checkBounds) {
164                                        TypeSubstitutor substitutor = TypeSubstitutor.create(result[0]);
165                                        for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
166                                            TypeParameterDescriptor parameter = parameters.get(i);
167                                            JetType argument = arguments.get(i).getType();
168                                            JetTypeReference typeReference = type.getTypeArguments().get(i).getTypeReference();
169    
170                                            if (typeReference != null) {
171                                                descriptorResolver.checkBounds(typeReference, argument, parameter, substitutor, trace);
172                                            }
173                                        }
174                                    }
175                                }
176                            }
177                        }
178                    }
179    
180                    @Override
181                    public void visitNullableType(JetNullableType nullableType) {
182                        JetType baseType = resolveTypeElement(scope, annotations, nullableType.getInnerType(), trace, checkBounds);
183                        if (baseType.isNullable()) {
184                            trace.report(REDUNDANT_NULLABLE.on(nullableType));
185                        }
186                        else if (TypeUtils.hasNullableSuperType(baseType)) {
187                            trace.report(BASE_WITH_NULLABLE_UPPER_BOUND.on(nullableType, baseType));
188                        }
189                        result[0] = TypeUtils.makeNullable(baseType);
190                    }
191    
192                    @Override
193                    public void visitFunctionType(JetFunctionType type) {
194                        JetTypeReference receiverTypeRef = type.getReceiverTypeRef();
195                        JetType receiverType = receiverTypeRef == null ? null : resolveType(scope, receiverTypeRef, trace, checkBounds);
196    
197                        List<JetType> parameterTypes = new ArrayList<JetType>();
198                        for (JetParameter parameter : type.getParameters()) {
199                            parameterTypes.add(resolveType(scope, parameter.getTypeReference(), trace, checkBounds));
200                        }
201    
202                        JetTypeReference returnTypeRef = type.getReturnTypeRef();
203                        JetType returnType;
204                        if (returnTypeRef != null) {
205                            returnType = resolveType(scope, returnTypeRef, trace, checkBounds);
206                        }
207                        else {
208                            returnType = KotlinBuiltIns.getInstance().getUnitType();
209                        }
210                        result[0] = KotlinBuiltIns.getInstance().getFunctionType(annotations, receiverType, parameterTypes, returnType);
211                    }
212    
213                    @Override
214                    public void visitJetElement(JetElement element) {
215                        trace.report(UNSUPPORTED.on(element, "Self-types are not supported yet"));
216    //                    throw new IllegalArgumentException("Unsupported type: " + element);
217                    }
218                });
219            }
220            if (result[0] == null) {
221                return ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText());
222            }
223            return result[0];
224        }
225    
226        private static boolean rhsOfIsExpression(@NotNull JetUserType type) {
227            // Look for the FIRST expression containing this type
228            JetExpression outerExpression = PsiTreeUtil.getParentOfType(type, JetExpression.class);
229            if (outerExpression instanceof JetIsExpression) {
230                JetIsExpression isExpression = (JetIsExpression) outerExpression;
231                // If this expression is JetIsExpression, and the type is the outermost on the RHS
232                if (type.getParent() == isExpression.getTypeRef()) {
233                    return true;
234                }
235            }
236            return false;
237        }
238    
239        private static boolean rhsOfIsPattern(@NotNull JetUserType type) {
240            // Look for the is-pattern containing this type
241            JetWhenConditionIsPattern outerPattern = PsiTreeUtil.getParentOfType(type, JetWhenConditionIsPattern.class, false, JetExpression.class);
242            if (outerPattern == null) return false;
243            // We are interested only in the outermost type on the RHS
244            return type.getParent() == outerPattern.getTypeRef();
245        }
246    
247        private JetScope getScopeForTypeParameter(final TypeParameterDescriptor typeParameterDescriptor, boolean checkBounds) {
248            if (checkBounds) {
249                return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
250            }
251            else {
252                return new LazyScopeAdapter(new RecursionIntolerantLazyValue<JetScope>() {
253                    @Override
254                    protected JetScope compute() {
255                        return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
256                    }
257                });
258            }
259        }
260    
261        private List<JetType> resolveTypes(JetScope scope, List<JetTypeReference> argumentElements, BindingTrace trace, boolean checkBounds) {
262            List<JetType> arguments = new ArrayList<JetType>();
263            for (JetTypeReference argumentElement : argumentElements) {
264                arguments.add(resolveType(scope, argumentElement, trace, checkBounds));
265            }
266            return arguments;
267        }
268    
269        @NotNull
270        private List<TypeProjection> resolveTypeProjections(JetScope scope, TypeConstructor constructor, List<JetTypeProjection> argumentElements, BindingTrace trace, boolean checkBounds) {
271            List<TypeProjection> arguments = new ArrayList<TypeProjection>();
272            for (int i = 0, argumentElementsSize = argumentElements.size(); i < argumentElementsSize; i++) {
273                JetTypeProjection argumentElement = argumentElements.get(i);
274    
275                JetProjectionKind projectionKind = argumentElement.getProjectionKind();
276                JetType type;
277                if (projectionKind == JetProjectionKind.STAR) {
278                    List<TypeParameterDescriptor> parameters = constructor.getParameters();
279                    if (parameters.size() > i) {
280                        TypeParameterDescriptor parameterDescriptor = parameters.get(i);
281                        arguments.add(SubstitutionUtils.makeStarProjection(parameterDescriptor));
282                    }
283                    else {
284                        arguments.add(new TypeProjection(OUT_VARIANCE, ErrorUtils.createErrorType("*")));
285                    }
286                }
287                else {
288                    // TODO : handle the Foo<in *> case
289                    type = resolveType(scope, argumentElement.getTypeReference(), trace, checkBounds);
290                    Variance kind = resolveProjectionKind(projectionKind);
291                    if (constructor.getParameters().size() > i) {
292                        TypeParameterDescriptor parameterDescriptor = constructor.getParameters().get(i);
293                        if (kind != INVARIANT && parameterDescriptor.getVariance() != INVARIANT) {
294                            if (kind == parameterDescriptor.getVariance()) {
295                                trace.report(REDUNDANT_PROJECTION.on(argumentElement, constructor.getDeclarationDescriptor()));
296                            }
297                            else {
298                                trace.report(CONFLICTING_PROJECTION.on(argumentElement, constructor.getDeclarationDescriptor()));
299                            }
300                        }
301                    }
302                    arguments.add(new TypeProjection(kind, type));
303                }
304            }
305            return arguments;
306        }
307    
308        @NotNull
309        public static Variance resolveProjectionKind(@NotNull JetProjectionKind projectionKind) {
310            Variance kind = null;
311            switch (projectionKind) {
312                case IN:
313                    kind = IN_VARIANCE;
314                    break;
315                case OUT:
316                    kind = OUT_VARIANCE;
317                    break;
318                case NONE:
319                    kind = INVARIANT;
320                    break;
321                default:
322                    // NOTE: Star projections must be handled before this method is called
323                    throw new IllegalStateException("Illegal projection kind:" + projectionKind);
324            }
325            return kind;
326        }
327    
328        @Nullable
329        public ClassifierDescriptor resolveClass(JetScope scope, JetUserType userType, BindingTrace trace) {
330            Collection<? extends DeclarationDescriptor> descriptors = qualifiedExpressionResolver.lookupDescriptorsForUserType(userType, scope, trace);
331            for (DeclarationDescriptor descriptor : descriptors) {
332                if (descriptor instanceof ClassifierDescriptor) {
333                    ImportsResolver.reportPlatformClassMappedToKotlin(moduleDescriptor, trace, userType, descriptor);
334                    return (ClassifierDescriptor) descriptor;
335                }
336            }
337            return null;
338        }
339    
340        @NotNull
341        private static String allStarProjectionsString(@NotNull TypeConstructor constructor) {
342            int size = constructor.getParameters().size();
343            assert size != 0 : "No projections possible for a nilary type constructor" + constructor;
344            ClassifierDescriptor declarationDescriptor = constructor.getDeclarationDescriptor();
345            assert declarationDescriptor != null : "No declaration descriptor for type constructor " + constructor;
346            String name = declarationDescriptor.getName().asString();
347    
348            return TypeUtils.getTypeNameAndStarProjectionsString(name, size);
349        }
350    }