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 kotlin.Function0;
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.Annotations;
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    
030    import javax.inject.Inject;
031    import java.util.ArrayList;
032    import java.util.Collections;
033    import java.util.List;
034    
035    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
036    import static org.jetbrains.jet.lang.resolve.PossiblyBareType.type;
037    import static org.jetbrains.jet.lang.types.Variance.*;
038    import static org.jetbrains.jet.storage.LockBasedStorageManager.NO_LOCKS;
039    
040    public class TypeResolver {
041    
042        private AnnotationResolver annotationResolver;
043        private QualifiedExpressionResolver qualifiedExpressionResolver;
044        private ModuleDescriptor moduleDescriptor;
045    
046        @Inject
047        public void setAnnotationResolver(AnnotationResolver annotationResolver) {
048            this.annotationResolver = annotationResolver;
049        }
050    
051        @Inject
052        public void setQualifiedExpressionResolver(QualifiedExpressionResolver qualifiedExpressionResolver) {
053            this.qualifiedExpressionResolver = qualifiedExpressionResolver;
054        }
055    
056        @Inject
057        public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
058            this.moduleDescriptor = moduleDescriptor;
059        }
060    
061        @NotNull
062        public JetType resolveType(@NotNull JetScope scope, @NotNull JetTypeReference typeReference, BindingTrace trace, boolean checkBounds) {
063            // bare types are not allowed
064            return resolveType(new TypeResolutionContext(scope, trace, checkBounds, false), typeReference);
065        }
066    
067        @NotNull
068        public JetType resolveType(@NotNull TypeResolutionContext c, @NotNull JetTypeReference typeReference) {
069            assert !c.allowBareTypes : "Use resolvePossiblyBareType() when bare types are allowed";
070            return resolvePossiblyBareType(c, typeReference).getActualType();
071        }
072    
073        @NotNull
074        public PossiblyBareType resolvePossiblyBareType(@NotNull TypeResolutionContext c, @NotNull JetTypeReference typeReference) {
075            JetType cachedType = c.trace.getBindingContext().get(BindingContext.TYPE, typeReference);
076            if (cachedType != null) return type(cachedType);
077    
078            Annotations annotations = annotationResolver.getResolvedAnnotations(typeReference.getAnnotations(), c.trace);
079    
080            JetTypeElement typeElement = typeReference.getTypeElement();
081            PossiblyBareType type = resolveTypeElement(c, annotations, typeElement);
082            if (!type.isBare()) {
083                c.trace.record(BindingContext.TYPE, typeReference, type.getActualType());
084            }
085            c.trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, c.scope);
086    
087            return type;
088        }
089    
090        @NotNull
091        private PossiblyBareType resolveTypeElement(
092                final TypeResolutionContext c,
093                final Annotations annotations,
094                JetTypeElement typeElement
095        ) {
096    
097            final PossiblyBareType[] result = new PossiblyBareType[1];
098            if (typeElement != null) {
099                typeElement.accept(new JetVisitorVoid() {
100                    @Override
101                    public void visitUserType(@NotNull JetUserType type) {
102                        JetSimpleNameExpression referenceExpression = type.getReferenceExpression();
103                        String referencedName = type.getReferencedName();
104                        if (referenceExpression == null || referencedName == null) {
105                            return;
106                        }
107    
108                        ClassifierDescriptor classifierDescriptor = resolveClass(c.scope, type, c.trace);
109                        if (classifierDescriptor == null) {
110                            resolveTypeProjections(c, ErrorUtils.createErrorType("No type").getConstructor(), type.getTypeArguments());
111                            return;
112                        }
113    
114                        c.trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, classifierDescriptor);
115    
116                        if (classifierDescriptor instanceof TypeParameterDescriptor) {
117                            TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) classifierDescriptor;
118    
119                            JetScope scopeForTypeParameter = getScopeForTypeParameter(c, typeParameterDescriptor);
120                            if (scopeForTypeParameter instanceof ErrorUtils.ErrorScope) {
121                                result[0] = type(ErrorUtils.createErrorType("?"));
122                            }
123                            else {
124                                result[0] = type(new JetTypeImpl(
125                                        annotations,
126                                        typeParameterDescriptor.getTypeConstructor(),
127                                        TypeUtils.hasNullableLowerBound(typeParameterDescriptor),
128                                        Collections.<TypeProjection>emptyList(),
129                                        scopeForTypeParameter
130                                ));
131                            }
132    
133                            resolveTypeProjections(c, ErrorUtils.createErrorType("No type").getConstructor(), type.getTypeArguments());
134    
135                            DeclarationDescriptor containing = typeParameterDescriptor.getContainingDeclaration();
136                            if (containing instanceof ClassDescriptor) {
137                                DescriptorResolver.checkHasOuterClassInstance(c.scope, c.trace, referenceExpression, (ClassDescriptor) containing);
138                            }
139                        }
140                        else if (classifierDescriptor instanceof ClassDescriptor) {
141                            ClassDescriptor classDescriptor = (ClassDescriptor) classifierDescriptor;
142    
143                            TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor();
144                            List<TypeProjection> arguments = resolveTypeProjections(c, typeConstructor, type.getTypeArguments());
145                            List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
146                            int expectedArgumentCount = parameters.size();
147                            int actualArgumentCount = arguments.size();
148                            if (ErrorUtils.isError(classDescriptor)) {
149                                result[0] = type(ErrorUtils.createErrorType("[Error type: " + typeConstructor + "]"));
150                            }
151                            else {
152                                if (actualArgumentCount != expectedArgumentCount) {
153                                    if (actualArgumentCount == 0) {
154                                        // See docs for PossiblyBareType
155                                        if (c.allowBareTypes) {
156                                            result[0] = PossiblyBareType.bare(typeConstructor, false);
157                                            return;
158                                        }
159                                        c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type, expectedArgumentCount));
160                                    }
161                                    else {
162                                        c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type.getTypeArgumentList(), expectedArgumentCount));
163                                    }
164                                }
165                                else {
166                                    JetTypeImpl resultingType = new JetTypeImpl(
167                                            annotations,
168                                            typeConstructor,
169                                            false,
170                                            arguments,
171                                            classDescriptor.getMemberScope(arguments)
172                                    );
173                                    result[0] = type(resultingType);
174                                    if (c.checkBounds) {
175                                        TypeSubstitutor substitutor = TypeSubstitutor.create(resultingType);
176                                        for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
177                                            TypeParameterDescriptor parameter = parameters.get(i);
178                                            JetType argument = arguments.get(i).getType();
179                                            JetTypeReference typeReference = type.getTypeArguments().get(i).getTypeReference();
180    
181                                            if (typeReference != null) {
182                                                DescriptorResolver.checkBounds(typeReference, argument, parameter, substitutor, c.trace);
183                                            }
184                                        }
185                                    }
186                                }
187                            }
188                        }
189                    }
190    
191                    @Override
192                    public void visitNullableType(@NotNull JetNullableType nullableType) {
193                        PossiblyBareType baseType = resolveTypeElement(c, annotations, nullableType.getInnerType());
194                        if (baseType.isNullable()) {
195                            c.trace.report(REDUNDANT_NULLABLE.on(nullableType));
196                        }
197                        else if (!baseType.isBare() && TypeUtils.hasNullableSuperType(baseType.getActualType())) {
198                            c.trace.report(BASE_WITH_NULLABLE_UPPER_BOUND.on(nullableType, baseType.getActualType()));
199                        }
200                        result[0] = baseType.makeNullable();
201                    }
202    
203                    @Override
204                    public void visitFunctionType(@NotNull JetFunctionType type) {
205                        JetTypeReference receiverTypeRef = type.getReceiverTypeReference();
206                        JetType receiverType = receiverTypeRef == null ? null : resolveType(c.noBareTypes(), receiverTypeRef);
207    
208                        List<JetType> parameterTypes = new ArrayList<JetType>();
209                        for (JetParameter parameter : type.getParameters()) {
210                            parameterTypes.add(resolveType(c.noBareTypes(), parameter.getTypeReference()));
211                        }
212    
213                        JetTypeReference returnTypeRef = type.getReturnTypeReference();
214                        JetType returnType;
215                        if (returnTypeRef != null) {
216                            returnType = resolveType(c.noBareTypes(), returnTypeRef);
217                        }
218                        else {
219                            returnType = KotlinBuiltIns.getInstance().getUnitType();
220                        }
221                        result[0] = type(KotlinBuiltIns.getInstance().getFunctionType(annotations, receiverType, parameterTypes, returnType));
222                    }
223    
224                    @Override
225                    public void visitJetElement(@NotNull JetElement element) {
226                        c.trace.report(UNSUPPORTED.on(element, "Self-types are not supported yet"));
227                    }
228                });
229            }
230            if (result[0] == null) {
231                return type(ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText()));
232            }
233            return result[0];
234        }
235    
236        private JetScope getScopeForTypeParameter(TypeResolutionContext c, final TypeParameterDescriptor typeParameterDescriptor) {
237            if (c.checkBounds) {
238                return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
239            }
240            else {
241                return new LazyScopeAdapter(NO_LOCKS.createLazyValue(new Function0<JetScope>() {
242                    @Override
243                    public JetScope invoke() {
244                        return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
245                    }
246                }));
247            }
248        }
249    
250        @NotNull
251        private List<TypeProjection> resolveTypeProjections(
252                TypeResolutionContext c,
253                TypeConstructor constructor,
254                List<JetTypeProjection> argumentElements
255        ) {
256            List<TypeProjection> arguments = new ArrayList<TypeProjection>();
257            for (int i = 0, argumentElementsSize = argumentElements.size(); i < argumentElementsSize; i++) {
258                JetTypeProjection argumentElement = argumentElements.get(i);
259    
260                JetProjectionKind projectionKind = argumentElement.getProjectionKind();
261                JetType type;
262                if (projectionKind == JetProjectionKind.STAR) {
263                    List<TypeParameterDescriptor> parameters = constructor.getParameters();
264                    if (parameters.size() > i) {
265                        TypeParameterDescriptor parameterDescriptor = parameters.get(i);
266                        arguments.add(TypeUtils.makeStarProjection(parameterDescriptor));
267                    }
268                    else {
269                        arguments.add(new TypeProjectionImpl(OUT_VARIANCE, ErrorUtils.createErrorType("*")));
270                    }
271                }
272                else {
273                    // TODO : handle the Foo<in *> case
274                    type = resolveType(c.noBareTypes(), argumentElement.getTypeReference());
275                    Variance kind = resolveProjectionKind(projectionKind);
276                    if (constructor.getParameters().size() > i) {
277                        TypeParameterDescriptor parameterDescriptor = constructor.getParameters().get(i);
278                        if (kind != INVARIANT && parameterDescriptor.getVariance() != INVARIANT) {
279                            if (kind == parameterDescriptor.getVariance()) {
280                                c.trace.report(REDUNDANT_PROJECTION.on(argumentElement, constructor.getDeclarationDescriptor()));
281                            }
282                            else {
283                                c.trace.report(CONFLICTING_PROJECTION.on(argumentElement, constructor.getDeclarationDescriptor()));
284                            }
285                        }
286                    }
287                    arguments.add(new TypeProjectionImpl(kind, type));
288                }
289            }
290            return arguments;
291        }
292    
293        @NotNull
294        public static Variance resolveProjectionKind(@NotNull JetProjectionKind projectionKind) {
295            Variance kind = null;
296            switch (projectionKind) {
297                case IN:
298                    kind = IN_VARIANCE;
299                    break;
300                case OUT:
301                    kind = OUT_VARIANCE;
302                    break;
303                case NONE:
304                    kind = INVARIANT;
305                    break;
306                default:
307                    // NOTE: Star projections must be handled before this method is called
308                    throw new IllegalStateException("Illegal projection kind:" + projectionKind);
309            }
310            return kind;
311        }
312    
313        @Nullable
314        public ClassifierDescriptor resolveClass(JetScope scope, JetUserType userType, BindingTrace trace) {
315            for (DeclarationDescriptor descriptor : qualifiedExpressionResolver.lookupDescriptorsForUserType(userType, scope, trace)) {
316                if (descriptor instanceof ClassifierDescriptor) {
317                    ImportsResolver.reportPlatformClassMappedToKotlin(moduleDescriptor, trace, userType, descriptor);
318                    return (ClassifierDescriptor) descriptor;
319                }
320            }
321            return null;
322        }
323    }