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 }