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