Make 'hasDefaultValue' an extension on ValueParameterDescriptor

To avoid storing a Boolean and a boolean. It isn't called frequently enough to
justify this wasted space for each parameter of every function out there
This commit is contained in:
Alexander Udalov
2015-08-06 03:21:46 +03:00
parent 8dddce5ac5
commit 942ab9ef6d
18 changed files with 72 additions and 82 deletions
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -89,7 +89,7 @@ public class DefaultParameterValueSubstitutor(val state: GenerationState) {
}
private fun FunctionDescriptor.countDefaultParameters() =
getValueParameters().count { it.hasDefaultValue() }
valueParameters.count { it.hasDefaultValue() }
/**
* Generates an overload for [functionDescriptor] that substitutes default values for the last
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.*;
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import java.util.List;
import java.util.Map;
@@ -263,7 +264,7 @@ public class ValueArgumentsToParametersMapper {
List<ValueParameterDescriptor> valueParameters = candidateCall.getCandidateDescriptor().getValueParameters();
for (ValueParameterDescriptor valueParameter : valueParameters) {
if (!usedParameters.contains(valueParameter)) {
if (valueParameter.hasDefaultValue()) {
if (DescriptorUtilPackage.hasDefaultValue(valueParameter)) {
candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT);
}
else if (valueParameter.getVarargElementType() != null) {
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.FunctionAnalyzerExtension;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import java.util.List;
@@ -75,17 +75,15 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz
@NotNull JetFunction function,
@NotNull BindingTrace trace
) {
int index = 0;
List<JetParameter> jetParameters = function.getValueParameters();
for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
if (parameter.hasDefaultValue()) {
JetParameter jetParameter = jetParameters.get(index);
if (DescriptorUtilPackage.hasDefaultValue(parameter)) {
JetParameter jetParameter = jetParameters.get(parameter.getIndex());
//report not supported default only on inlinable lambda and on parameter with inherited default (there is some problems to inline it)
if (checkInlinableParameter(parameter, jetParameter, functionDescriptor, null) || !parameter.declaresDefaultValue()) {
trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(jetParameter, jetParameter, functionDescriptor));
}
}
index++;
}
}
@@ -90,16 +90,7 @@ public abstract class LazyJavaScope(
computeNonDeclaredFunctions(result, name)
val enhancedResult = enhanceSignatures(result)
// Make sure that lazy things are computed before we release the lock
for (f in enhancedResult) {
for (p in f.getValueParameters()) {
p.hasDefaultValue()
}
}
enhancedResult.toReadOnlyList()
enhanceSignatures(result).toReadOnlyList()
}
protected data class MethodSignatureData(
@@ -36,21 +36,13 @@ public interface ValueParameterDescriptor extends VariableDescriptor, ParameterD
int getIndex();
/**
* The front-end relies on this property when resolving function calls
*
* @return {@code true} iff the parameter has a default value, i.e. declares it or inherits
* by overriding a parameter in an overridden function.
*/
boolean hasDefaultValue();
/**
* The back-end should relies on this property when generating function signatures
*
* @return {@code true} iff the parameter declares a default value, i.e. explicitly specifies it in the function header
* @return true iff this parameter belongs to a declared function (not a fake override) and declares the default value,
* i.e. explicitly specifies it in the function signature. Also see 'hasDefaultValue' extension in DescriptorUtils.kt
*/
boolean declaresDefaultValue();
@Nullable JetType getVarargElementType();
@Nullable
JetType getVarargElementType();
@NotNull
@Override
@@ -29,14 +29,11 @@ import java.util.LinkedHashSet;
import java.util.Set;
public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements ValueParameterDescriptor {
private Boolean hasDefaultValue;
private final boolean declaresDefaultValue;
private final JetType varargElementType;
private final int index;
private final ValueParameterDescriptor original;
private final Set<ValueParameterDescriptor> overriddenDescriptors = new LinkedHashSet<ValueParameterDescriptor>(); // Linked is essential
private boolean overriddenDescriptorsLocked = false;
private final Set<? extends ValueParameterDescriptor> readOnlyOverriddenDescriptors = Collections.unmodifiableSet(overriddenDescriptors);
public ValueParameterDescriptorImpl(
@NotNull CallableDescriptor containingDeclaration,
@@ -62,43 +59,16 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
return (CallableDescriptor) super.getContainingDeclaration();
}
public void setType(@NotNull JetType type) {
setOutType(type);
}
@Override
public int getIndex() {
return index;
}
@Override
public boolean hasDefaultValue() {
computeDefaultValuePresence();
return hasDefaultValue;
}
@Override
public boolean declaresDefaultValue() {
return declaresDefaultValue && ((CallableMemberDescriptor) getContainingDeclaration()).getKind().isReal();
}
private void computeDefaultValuePresence() {
if (hasDefaultValue != null) return;
overriddenDescriptorsLocked = true;
if (declaresDefaultValue) {
hasDefaultValue = true;
}
else {
for (ValueParameterDescriptor descriptor : overriddenDescriptors) {
if (descriptor.hasDefaultValue()) {
hasDefaultValue = true;
return;
}
}
hasDefaultValue = false;
}
}
@Nullable
@Override
public JetType getVarargElementType() {
@@ -146,13 +116,11 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@NotNull
@Override
public Set<? extends ValueParameterDescriptor> getOverriddenDescriptors() {
return readOnlyOverriddenDescriptors;
return Collections.unmodifiableSet(overriddenDescriptors);
}
@Override
public void addOverriddenDescriptor(@NotNull ValueParameterDescriptor overridden) {
assert !overriddenDescriptorsLocked : "Adding more overridden descriptors is not allowed at this point: " +
"the presence of the default value has already been calculated";
overriddenDescriptors.add(overridden);
}
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.constants.AnnotationValue
import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.ErrorUtils.UninferredParameterTypeConstructor
import org.jetbrains.kotlin.types.TypeUtils.CANT_INFER_FUNCTION_PARAM_TYPE
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.BooleanValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.utils.DFS
public fun ClassDescriptor.getClassObjectReferenceTarget(): ClassDescriptor = getCompanionObjectDescriptor() ?: this
@@ -145,6 +146,32 @@ public fun CallableDescriptor.getOwnerForEffectiveDispatchReceiverParameter(): D
return getDispatchReceiverParameter()?.getContainingDeclaration()
}
/**
* @return `true` iff the parameter has a default value, i.e. declares it or inherits by overriding a parameter which has a default value.
*/
public fun ValueParameterDescriptor.hasDefaultValue(): Boolean {
val handler = object : DFS.AbstractNodeHandler<ValueParameterDescriptor, Boolean>() {
var result = false
override fun beforeChildren(current: ValueParameterDescriptor): Boolean {
result = result || current.declaresDefaultValue()
return !result
}
override fun result() = result
}
DFS.dfs(
listOf(this),
DFS.Neighbors<ValueParameterDescriptor> { current ->
current.overriddenDescriptors.map(ValueParameterDescriptor::getOriginal)
},
handler
)
return handler.result()
}
private fun Annotated.isAnnotationPropertyTrue(name: String, defaultValue: Boolean = false): Boolean {
val annotationEntryDescriptor = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation) ?: return defaultValue
val repeatableArgumentValue = annotationEntryDescriptor.allValueArguments.entrySet().firstOrNull {
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.hasTypeMismatchErrorOnParameter
import org.jetbrains.kotlin.resolve.calls.callUtil.hasUnmappedArguments
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.types.ErrorUtils
private val RED_TEMPLATE = "<font color=red><b>%s</b></font>"
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
@@ -24,10 +24,10 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
import org.jetbrains.kotlin.idea.completion.*
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.checker.JetTypeChecker
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import java.util.ArrayList
import java.util.HashMap
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude;
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter;
@@ -164,7 +165,7 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith
builder.append(parameter.getName())
.append(": ")
.append(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getActualParameterType(parameter)));
if (parameter.hasDefaultValue()) {
if (DescriptorUtilPackage.hasDefaultValue(parameter)) {
PsiElement parameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(parameter);
builder.append(" = ").append(getDefaultExpressionString(parameterDeclaration));
}
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention
import org.jetbrains.kotlin.idea.intentions.setType
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
@@ -52,6 +51,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.psi.JetClassOrObject;
import org.jetbrains.kotlin.psi.JetParameter;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import java.util.ArrayList;
import java.util.List;
@@ -67,7 +68,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
JsExpression argumentValue;
JsExpression parameterValue = new JsNameRef(paramName);
if (!constructorParam.hasValOrVar()) {
assert !function.getValueParameters().get(i).hasDefaultValue();
assert !DescriptorUtilPackage.hasDefaultValue(function.getValueParameters().get(i));
// Caller cannot rely on default value and pass undefined here.
argumentValue = parameterValue;
}
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.psi.JetDeclarationWithBody;
import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import java.util.HashMap;
import java.util.List;
@@ -148,7 +149,7 @@ public final class FunctionTranslator extends AbstractTranslator {
public static void addParameters(List<JsParameter> list, FunctionDescriptor descriptor, TranslationContext context) {
for (ValueParameterDescriptor valueParameter : descriptor.getValueParameters()) {
JsParameter jsParameter = new JsParameter(context.getNameForDescriptor(valueParameter));
MetadataPackage.setHasDefaultValue(jsParameter, valueParameter.hasDefaultValue());
MetadataPackage.setHasDefaultValue(jsParameter, DescriptorUtilPackage.hasDefaultValue(valueParameter));
list.add(jsParameter);
}
}
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeUtils;
@@ -176,7 +177,8 @@ public final class BindingUtils {
@NotNull ValueParameterDescriptor parameterDescriptor
) {
ValueParameterDescriptor result = parameterDescriptor;
assert result.hasDefaultValue() : message(parameterDescriptor, "Unsupplied parameter must have default value");
assert DescriptorUtilPackage.hasDefaultValue(result) : message(parameterDescriptor, "Unsupplied parameter must have default value");
// TODO: this seems incorrect, as the default value may come from _not the first_ overridden parameter
while (!result.declaresDefaultValue()) {
result = result.getOverriddenDescriptors().iterator().next();
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.js.translate.general.Translation;
import org.jetbrains.kotlin.js.translate.utils.mutator.Mutator;
import org.jetbrains.kotlin.psi.JetDeclarationWithBody;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import org.jetbrains.kotlin.types.JetType;
import java.util.ArrayList;
@@ -48,20 +49,23 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
@NotNull
public static List<JsStatement> setDefaultValueForArguments(@NotNull FunctionDescriptor descriptor,
@NotNull TranslationContext functionBodyContext) {
List<JsStatement> result = new ArrayList<JsStatement>();
for (ValueParameterDescriptor valueParameter : descriptor.getValueParameters()) {
if (valueParameter.hasDefaultValue()) {
JsNameRef jsNameRef = functionBodyContext.getNameForDescriptor(valueParameter).makeRef();
JetExpression defaultArgument = getDefaultArgument(valueParameter);
JsBlock defaultArgBlock = new JsBlock();
JsExpression defaultValue = Translation.translateAsExpression(defaultArgument, functionBodyContext, defaultArgBlock);
JsStatement assignStatement = assignment(jsNameRef, defaultValue).makeStmt();
JsStatement thenStatement = JsAstUtils.mergeStatementInBlockIfNeeded(assignStatement, defaultArgBlock);
JsBinaryOperation checkArgIsUndefined = equality(jsNameRef, functionBodyContext.namer().getUndefinedExpression());
JsIf jsIf = JsAstUtils.newJsIf(checkArgIsUndefined, thenStatement);
result.add(jsIf);
}
List<ValueParameterDescriptor> valueParameters = descriptor.getValueParameters();
List<JsStatement> result = new ArrayList<JsStatement>(valueParameters.size());
for (ValueParameterDescriptor valueParameter : valueParameters) {
if (!DescriptorUtilPackage.hasDefaultValue(valueParameter)) continue;
JsNameRef jsNameRef = functionBodyContext.getNameForDescriptor(valueParameter).makeRef();
JetExpression defaultArgument = getDefaultArgument(valueParameter);
JsBlock defaultArgBlock = new JsBlock();
JsExpression defaultValue = Translation.translateAsExpression(defaultArgument, functionBodyContext, defaultArgBlock);
JsStatement assignStatement = assignment(jsNameRef, defaultValue).makeStmt();
JsStatement thenStatement = JsAstUtils.mergeStatementInBlockIfNeeded(assignStatement, defaultArgBlock);
JsBinaryOperation checkArgIsUndefined = equality(jsNameRef, functionBodyContext.namer().getUndefinedExpression());
JsIf jsIf = JsAstUtils.newJsIf(checkArgIsUndefined, thenStatement);
result.add(jsIf);
}
return result;
}