Support single-underscore named variables in JVM backend

There are mainly two kind of changes:
- skipping 'componentX' calls for destructuring entries named _
- fixing local variable table for them
 - skip entries for destructuring entries named _
 - use $noName_<i> format for lambda parameters named _

 #KT-3824 Fixed
 #KT-2783 Fixed
This commit is contained in:
Denis Zharkov
2016-10-20 17:23:42 +03:00
parent 544d8f5b66
commit a9fcee098d
18 changed files with 355 additions and 7 deletions
@@ -44,7 +44,7 @@ class ClosureGenerationStrategy(
for (parameterDescriptor in codegen.context.functionDescriptor.valueParameters) {
if (parameterDescriptor !is ValueParameterDescriptorImpl.WithDestructuringDeclaration) continue
for (entry in parameterDescriptor.destructuringVariables) {
for (entry in parameterDescriptor.destructuringVariables.filterOutDescriptorsWithSpecialNames()) {
codegen.myFrameMap.enter(entry, codegen.typeMapper.mapType(entry.type))
}
@@ -775,9 +775,19 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
private void generateDestructuringDeclaration(@NotNull KtDestructuringDeclaration destructuringDeclaration) {
final Label destructuringStartLabel = new Label();
for (KtDestructuringDeclarationEntry variableDeclaration : destructuringDeclaration.getEntries()) {
final VariableDescriptor componentDescriptor = bindingContext.get(VARIABLE, variableDeclaration);
List<VariableDescriptor> componentDescriptors =
CollectionsKt.map(
destructuringDeclaration.getEntries(),
new Function1<KtDestructuringDeclarationEntry, VariableDescriptor>() {
@Override
public VariableDescriptor invoke(KtDestructuringDeclarationEntry entry) {
return getVariableDescriptorNotNull(entry);
}
}
);
for (final VariableDescriptor componentDescriptor : CodegenUtilKt.filterOutDescriptorsWithSpecialNames(componentDescriptors)) {
@SuppressWarnings("ConstantConditions") final Type componentAsmType = asmType(componentDescriptor.getReturnType());
final int componentVarIndex = myFrameMap.enter(componentDescriptor, componentAsmType);
scheduleLeaveVariable(new Runnable() {
@@ -1957,8 +1967,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
private void putLocalVariableIntoFrameMap(@NotNull KtVariableDeclaration statement) {
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement);
assert variableDescriptor != null : "Couldn't find variable declaration in binding context " + statement.getText();
VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(statement);
// Do not modify local variables table for variables like _ in val (_, y) = pair
// They always will have special name
if (variableDescriptor.getName().isSpecial()) return;
Type type = getVariableType(variableDescriptor);
int index = myFrameMap.enter(variableDescriptor, type);
@@ -2004,6 +2016,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
) {
final VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(statement);
// Do not modify local variables table for variables like _ in val (_, y) = pair
// They always will have special name
if (variableDescriptor.getName().isSpecial()) return;
final Type type = getVariableType(variableDescriptor);
final Label scopeStart = new Label();
@@ -3902,6 +3918,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration);
assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
Call call = makeFakeCall(receiver);
VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(variableDeclaration);
// Do not call `componentX` for destructuring entry called _
if (variableDescriptor.getName().isSpecial()) continue;
initializeLocalVariable(variableDeclaration, invokeFunction(call, resolvedCall, receiverStackValue));
}
}
@@ -46,9 +46,11 @@ import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.psi.KtFunction;
import org.jetbrains.kotlin.psi.KtNamedFunction;
import org.jetbrains.kotlin.psi.KtParameter;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
import org.jetbrains.kotlin.resolve.constants.ArrayValue;
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.constants.KClassValue;
@@ -563,7 +565,7 @@ public class FunctionCodegen {
parameterName =
destructuringVariables == null
? parameter.getName().asString()
? computeParameterName(i, parameter)
: "$" + joinParameterNames(destructuringVariables);
}
else {
@@ -583,7 +585,7 @@ public class FunctionCodegen {
List<VariableDescriptor> destructuringVariables = ValueParameterDescriptorImpl.getDestructuringVariablesOrNull(parameter);
if (destructuringVariables == null) continue;
for (VariableDescriptor entry : destructuringVariables) {
for (VariableDescriptor entry : CodegenUtilKt.filterOutDescriptorsWithSpecialNames(destructuringVariables)) {
Type type = typeMapper.mapType(entry.getType());
mv.visitLocalVariable(entry.getName().asString(), type.getDescriptor(), null, methodBegin, methodEnd, shift);
shift += type.getSize();
@@ -591,10 +593,21 @@ public class FunctionCodegen {
}
}
private static String computeParameterName(int i, ValueParameterDescriptor parameter) {
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(parameter);
if (element instanceof KtParameter && UnderscoreUtilKt.isSingleUnderscore((KtParameter) element)) {
return "$noName_" + i;
}
return parameter.getName().asString();
}
private static String joinParameterNames(@NotNull List<VariableDescriptor> variables) {
return org.jetbrains.kotlin.utils.StringsKt.join(CollectionsKt.map(variables, new Function1<VariableDescriptor, String>() {
@Override
public String invoke(VariableDescriptor descriptor) {
// stub for anonymous destructuring declaration entry
if (descriptor.getName().isSpecial()) return "$_$";
return descriptor.getName().asString();
}
}), "_");
@@ -255,3 +255,5 @@ private fun CallableDescriptor.isJvmStaticIn(predicate: (DeclarationDescriptor)
}
else -> predicate(containingDeclaration) && hasJvmStaticAnnotation()
}
fun Collection<VariableDescriptor>.filterOutDescriptorsWithSpecialNames() = filterNot { it.name.isSpecial }