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.codegen.binding;
018    
019    import com.intellij.openapi.util.Pair;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
023    import org.jetbrains.kotlin.descriptors.*;
024    import org.jetbrains.kotlin.types.KotlinType;
025    import org.jetbrains.org.objectweb.asm.Type;
026    
027    import java.util.*;
028    
029    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.getDirectMember;
030    
031    public final class MutableClosure implements CalculatedClosure {
032        private final ClassDescriptor closureClass;
033        private final ClassDescriptor enclosingClass;
034        private final CallableDescriptor enclosingFunWithReceiverDescriptor;
035    
036        private boolean captureThis;
037        private boolean captureEnclosingReceiver;
038    
039        private Map<DeclarationDescriptor, EnclosedValueDescriptor> captureVariables;
040        private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
041        private List<Pair<String, Type>> recordedFields;
042        private KotlinType captureReceiverType;
043        private boolean isSuspend;
044        private boolean isSuspendLambda;
045    
046        MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
047            this.closureClass = classDescriptor;
048            this.enclosingClass = enclosingClass;
049            this.enclosingFunWithReceiverDescriptor = enclosingExtensionMemberForClass(classDescriptor);
050        }
051    
052        @Nullable
053        private static CallableDescriptor enclosingExtensionMemberForClass(@NotNull ClassDescriptor classDescriptor) {
054            DeclarationDescriptor classContainer = classDescriptor.getContainingDeclaration();
055            if (classContainer instanceof CallableMemberDescriptor) {
056                CallableMemberDescriptor member = getDirectMember((CallableMemberDescriptor) classContainer);
057                if (member.getExtensionReceiverParameter() != null) {
058                    return member;
059                }
060            }
061            return null;
062        }
063    
064        @NotNull
065        @Override
066        public ClassDescriptor getClosureClass() {
067            return closureClass;
068        }
069    
070        @Nullable
071        public ClassDescriptor getEnclosingClass() {
072            return enclosingClass;
073        }
074    
075        @Override
076        public ClassDescriptor getCaptureThis() {
077            return captureThis ? enclosingClass : null;
078        }
079    
080        public void setCaptureThis() {
081            this.captureThis = true;
082        }
083    
084        @Override
085        public KotlinType getCaptureReceiverType() {
086            if (captureReceiverType != null) {
087                return captureReceiverType;
088            }
089    
090            if (captureEnclosingReceiver) {
091                ReceiverParameterDescriptor parameter = getEnclosingReceiverDescriptor();
092                assert parameter != null : "Receiver parameter should exist in " + enclosingFunWithReceiverDescriptor;
093                return parameter.getType();
094            }
095    
096            return null;
097        }
098    
099        public void setCaptureReceiver() {
100            if (enclosingFunWithReceiverDescriptor == null) {
101                throw new IllegalStateException("Extension receiver parameter should exist");
102            }
103            this.captureEnclosingReceiver = true;
104        }
105    
106        @NotNull
107        @Override
108        public Map<DeclarationDescriptor, EnclosedValueDescriptor> getCaptureVariables() {
109            return captureVariables != null ? captureVariables : Collections.<DeclarationDescriptor, EnclosedValueDescriptor>emptyMap();
110        }
111    
112        public void setCaptureReceiverType(@NotNull KotlinType type) {
113            this.captureReceiverType = type;
114        }
115    
116        @NotNull
117        @Override
118        public List<Pair<String, Type>> getRecordedFields() {
119            return recordedFields != null ? recordedFields : Collections.<Pair<String, Type>>emptyList();
120        }
121    
122        @Override
123        public boolean isSuspend() {
124            return isSuspend;
125        }
126    
127        public void setSuspend(boolean suspend) {
128            this.isSuspend = suspend;
129        }
130    
131        @Override
132        public boolean isSuspendLambda() {
133            return isSuspendLambda;
134        }
135    
136        public void setSuspendLambda() {
137            isSuspendLambda = true;
138        }
139    
140        public void recordField(String name, Type type) {
141            if (recordedFields == null) {
142                recordedFields = new LinkedList<Pair<String, Type>>();
143            }
144            recordedFields.add(new Pair<String, Type>(name, type));
145        }
146    
147        public void captureVariable(EnclosedValueDescriptor value) {
148            if (captureVariables == null) {
149                captureVariables = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
150            }
151            captureVariables.put(value.getDescriptor(), value);
152        }
153    
154        public void setCapturedParameterOffsetInConstructor(DeclarationDescriptor descriptor, int offset) {
155            if (parameterOffsetInConstructor == null) {
156                parameterOffsetInConstructor = new LinkedHashMap<DeclarationDescriptor, Integer>();
157            }
158            parameterOffsetInConstructor.put(descriptor, offset);
159        }
160    
161        public int getCapturedParameterOffsetInConstructor(DeclarationDescriptor descriptor) {
162            Integer result = parameterOffsetInConstructor != null ? parameterOffsetInConstructor.get(descriptor) : null;
163            return result != null ? result.intValue() : -1;
164        }
165    
166        @Nullable
167        public ReceiverParameterDescriptor getEnclosingReceiverDescriptor() {
168            return enclosingFunWithReceiverDescriptor != null ? enclosingFunWithReceiverDescriptor.getExtensionReceiverParameter() : null;
169        }
170    }