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
017package org.jetbrains.jet.lang.types;
018
019import org.jetbrains.annotations.NotNull;
020import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
021import org.jetbrains.jet.lang.descriptors.annotations.AnnotatedImpl;
022import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
023import org.jetbrains.jet.lang.resolve.scopes.JetScope;
024import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
025
026import java.util.Collections;
027import java.util.Iterator;
028import java.util.List;
029
030public final class JetTypeImpl extends AnnotatedImpl implements JetType {
031
032    private final TypeConstructor constructor;
033    private final List<TypeProjection> arguments;
034    private final boolean nullable;
035    private final JetScope memberScope;
036
037    public JetTypeImpl(List<AnnotationDescriptor> annotations, TypeConstructor constructor, boolean nullable, @NotNull List<TypeProjection> arguments, JetScope memberScope) {
038        super(annotations);
039
040        if (memberScope instanceof ErrorUtils.ErrorScope) {
041            throw new IllegalStateException();
042        }
043
044        this.constructor = constructor;
045        this.nullable = nullable;
046        this.arguments = arguments;
047        this.memberScope = memberScope;
048    }
049
050    public JetTypeImpl(TypeConstructor constructor, JetScope memberScope) {
051        this(Collections.<AnnotationDescriptor>emptyList(), constructor, false, Collections.<TypeProjection>emptyList(), memberScope);
052    }
053
054    public JetTypeImpl(@NotNull ClassDescriptor classDescriptor) {
055        this(Collections.<AnnotationDescriptor>emptyList(),
056                classDescriptor.getTypeConstructor(),
057                false,
058                Collections.<TypeProjection>emptyList(),
059                classDescriptor.getMemberScope(Collections.<TypeProjection>emptyList()));
060    }
061
062    @NotNull
063    @Override
064    public TypeConstructor getConstructor() {
065        return constructor;
066    }
067
068    @NotNull
069    @Override
070    public List<TypeProjection> getArguments() {
071        return arguments;
072    }
073
074    @Override
075    public boolean isNullable() {
076        return nullable;
077    }
078
079    @NotNull
080    @Override
081    public JetScope getMemberScope() {
082        return memberScope;
083    }
084
085    @Override
086    public String toString() {
087        return constructor + (arguments.isEmpty() ? "" : "<" + argumentsToString() + ">") + (isNullable() ? "?" : "");
088    }
089
090    private StringBuilder argumentsToString() {
091        StringBuilder stringBuilder = new StringBuilder();
092        for (Iterator<TypeProjection> iterator = arguments.iterator(); iterator.hasNext();) {
093            TypeProjection argument = iterator.next();
094            stringBuilder.append(argument);
095            if (iterator.hasNext()) {
096                stringBuilder.append(", ");
097            }
098        }
099        return stringBuilder;
100    }
101
102    @Override
103    public boolean equals(Object o) {
104        if (this == o) return true;
105        if (!(o instanceof JetType)) return false;
106
107        JetType type = (JetType) o;
108
109        return nullable == type.isNullable() && JetTypeChecker.INSTANCE.equalTypes(this, type);
110    }
111
112    @Override
113    public int hashCode() {
114        int result = constructor != null ? constructor.hashCode() : 0;
115        result = 31 * result + arguments.hashCode();
116        result = 31 * result + (nullable ? 1 : 0);
117        return result;
118    }
119}