this() calls supported

properties integrated
This commit is contained in:
Andrey Breslav
2011-08-30 19:02:18 +04:00
parent aace514a35
commit 496549cab8
25 changed files with 1125 additions and 550 deletions
@@ -216,7 +216,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
HashSet<FunctionDescriptor> overridden = new HashSet<FunctionDescriptor>();
for (JetDeclaration declaration : myClass.getDeclarations()) {
if (declaration instanceof JetFunction) {
overridden.addAll(state.getBindingContext().get(BindingContext.FUNCTION, (JetNamedFunction) declaration).getOverriddenFunctions());
overridden.addAll(state.getBindingContext().get(BindingContext.FUNCTION, (JetNamedFunction) declaration).getOverriddenDescriptors());
}
}
@@ -0,0 +1,36 @@
package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
*/
public interface CallableDescriptor extends DeclarationDescriptor {
@Nullable
JetType getReceiverType();
@NotNull
List<TypeParameterDescriptor> getTypeParameters();
@NotNull
JetType getReturnType();
@NotNull
@Override
CallableDescriptor getOriginal();
@Override
CallableDescriptor substitute(TypeSubstitutor substitutor);
@NotNull
List<ValueParameterDescriptor> getValueParameters();
@NotNull
Set<? extends CallableDescriptor> getOverriddenDescriptors();
}
@@ -62,7 +62,7 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
public Set<? extends FunctionDescriptor> getOverriddenDescriptors() {
return Collections.emptySet();
}
@@ -1,39 +1,26 @@
package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
*/
public interface FunctionDescriptor extends DeclarationDescriptor {
public interface FunctionDescriptor extends CallableDescriptor {
@Override
@NotNull
DeclarationDescriptor getContainingDeclaration();
@Nullable
JetType getReceiverType();
@NotNull
List<TypeParameterDescriptor> getTypeParameters();
@NotNull
List<ValueParameterDescriptor> getValueParameters();
@NotNull
JetType getReturnType();
@NotNull
@Override
FunctionDescriptor getOriginal();
@Override
FunctionDescriptor substitute(TypeSubstitutor substitutor);
@Override
@NotNull
Set<? extends FunctionDescriptor> getOverriddenFunctions();
Set<? extends FunctionDescriptor> getOverriddenDescriptors();
}
@@ -65,7 +65,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
public Set<? extends FunctionDescriptor> getOverriddenDescriptors() {
return overriddenFunctions;
}
@@ -48,7 +48,7 @@ public class FunctionDescriptorUtil {
return unsubstitutedValueParameters.size();
}
private static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
public static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
Map<TypeConstructor, TypeProjection> result = new HashMap<TypeConstructor, TypeProjection>();
@@ -112,59 +112,6 @@ public class FunctionDescriptorUtil {
return parameterScope;
}
@NotNull
public static FunctionDescriptor substituteBounds(@NotNull FunctionDescriptor functionDescriptor) {
final List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
if (typeParameters.isEmpty()) return functionDescriptor;
final Map<TypeConstructor, TypeParameterDescriptor> typeConstructors = Maps.newHashMap();
for (TypeParameterDescriptor typeParameter : typeParameters) {
typeConstructors.put(typeParameter.getTypeConstructor(), typeParameter);
}
return functionDescriptor.substitute(new TypeSubstitutor(TypeSubstitution.EMPTY) {
@Override
public boolean inRange(@NotNull TypeConstructor typeConstructor) {
return typeConstructors.containsKey(typeConstructor);
}
@Override
public boolean isEmpty() {
return typeParameters.isEmpty();
}
@NotNull
@Override
public TypeSubstitution getSubstitution() {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public JetType safeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
JetType substituted = substitute(type, howThisTypeIsUsed);
if (substituted == null) {
return ErrorUtils.createErrorType("Substitution failed");
}
return substituted;
}
@Override
public JetType substitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
TypeParameterDescriptor typeParameterDescriptor = typeConstructors.get(type.getConstructor());
if (typeParameterDescriptor != null) {
switch (howThisTypeIsUsed) {
case INVARIANT:
return type;
case IN_VARIANCE:
throw new UnsupportedOperationException(); // TODO : lower bounds
case OUT_VARIANCE:
return typeParameterDescriptor.getDefaultType();
}
}
return super.substitute(type, howThisTypeIsUsed);
}
});
}
public static class OverrideCompatibilityInfo {
private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(false, "SUCCESS");
@@ -78,7 +78,8 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
}
@NotNull
public List<TypeParameterDescriptor> getTypeParemeters() {
@Override
public List<TypeParameterDescriptor> getTypeParameters() {
return typeParemeters;
}
@@ -87,6 +88,12 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
return receiverType;
}
@NotNull
@Override
public JetType getReturnType() {
return getOutType();
}
public boolean isVar() {
return isVar;
@@ -110,7 +117,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
@NotNull
@Override
public VariableDescriptor substitute(TypeSubstitutor substitutor) {
public PropertyDescriptor substitute(TypeSubstitutor substitutor) {
JetType originalInType = getInType();
JetType inType = originalInType == null ? null : substitutor.substitute(originalInType, Variance.IN_VARIANCE);
JetType originalOutType = getOutType();
@@ -24,7 +24,7 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor {
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
public Set<? extends FunctionDescriptor> getOverriddenDescriptors() {
return overriddenGetters;
}
@@ -33,7 +33,7 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor {
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
public Set<? extends FunctionDescriptor> getOverriddenDescriptors() {
return overriddenSetters;
}
@@ -8,7 +8,7 @@ import org.jetbrains.jet.lang.types.TypeSubstitutor;
/**
* @author abreslav
*/
public interface VariableDescriptor extends DeclarationDescriptor {
public interface VariableDescriptor extends CallableDescriptor {
/**
* @return <code>null</code> for write-only variables (i.e. properties), variable value type otherwise
*/
@@ -5,7 +5,9 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
@@ -44,4 +46,39 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i
protected void setOutType(JetType outType) {
this.outType = outType;
}
@Override
@NotNull
public VariableDescriptor getOriginal() {
return (VariableDescriptor) super.getOriginal();
}
@NotNull
@Override
public List<ValueParameterDescriptor> getValueParameters() {
return Collections.emptyList();
}
@NotNull
@Override
public Set<? extends CallableDescriptor> getOverriddenDescriptors() {
return Collections.emptySet();
}
@NotNull
@Override
public List<TypeParameterDescriptor> getTypeParameters() {
return Collections.emptyList();
}
@Override
public JetType getReceiverType() {
return null;
}
@NotNull
@Override
public JetType getReturnType() {
return getOutType();
}
}
@@ -1,7 +1,12 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.types.*;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
@@ -30,4 +35,58 @@ public class DescriptorUtils {
}
}, null);
}
@NotNull
public static <Descriptor extends CallableDescriptor> Descriptor substituteBounds(@NotNull Descriptor functionDescriptor) {
final List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
if (typeParameters.isEmpty()) return functionDescriptor;
final Map<TypeConstructor, TypeParameterDescriptor> typeConstructors = Maps.newHashMap();
for (TypeParameterDescriptor typeParameter : typeParameters) {
typeConstructors.put(typeParameter.getTypeConstructor(), typeParameter);
}
//noinspection unchecked
return (Descriptor) functionDescriptor.substitute(new TypeSubstitutor(TypeSubstitutor.TypeSubstitution.EMPTY) {
@Override
public boolean inRange(@NotNull TypeConstructor typeConstructor) {
return typeConstructors.containsKey(typeConstructor);
}
@Override
public boolean isEmpty() {
return typeParameters.isEmpty();
}
@NotNull
@Override
public TypeSubstitution getSubstitution() {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public JetType safeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
JetType substituted = substitute(type, howThisTypeIsUsed);
if (substituted == null) {
return ErrorUtils.createErrorType("Substitution failed");
}
return substituted;
}
@Override
public JetType substitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
TypeParameterDescriptor typeParameterDescriptor = typeConstructors.get(type.getConstructor());
if (typeParameterDescriptor != null) {
switch (howThisTypeIsUsed) {
case INVARIANT:
return type;
case IN_VARIANCE:
throw new UnsupportedOperationException(); // TODO : lower bounds
case OUT_VARIANCE:
return typeParameterDescriptor.getDefaultType();
}
}
return super.substitute(type, howThisTypeIsUsed);
}
});
}
}
@@ -580,7 +580,7 @@ public class TopDownAnalyzer {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
typeInferrer.getCallResolver().resolveCall(scopeForConstructor, null, call, NO_EXPECTED_TYPE);
typeInferrer.getCallResolver().resolveCall(trace, scopeForConstructor, null, call, NO_EXPECTED_TYPE);
}
else {
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
@@ -685,7 +685,7 @@ public class TopDownAnalyzer {
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
typeInferrerForInitializers.getCallResolver().resolveCall(functionInnerScope, null, call, NO_EXPECTED_TYPE);
typeInferrerForInitializers.getCallResolver().resolveCall(trace, functionInnerScope, null, call, NO_EXPECTED_TYPE);
}
}
@@ -693,14 +693,16 @@ public class TopDownAnalyzer {
public void visitDelegationToThisCall(JetDelegatorToThisCall call) {
// TODO : check that there's no recursion in this() calls
// TODO : check: if a this() call is present, no other initializers are allowed
// ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
// typeInferrerForInitializers.checkClassConstructorCall(
// functionInnerScope,
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
typeInferrerForInitializers.getCallResolver().resolveCall(trace,
functionInnerScope,
null, call, NO_EXPECTED_TYPE);
// call.getThisReference(),
// classDescriptor,
// classDescriptor.getDefaultType(),
// call);
trace.getErrorHandler().genericError(call.getNode(), "this-calls are not supported");
// trace.getErrorHandler().genericError(call.getNode(), "this-calls are not supported");
}
@Override
@@ -805,7 +807,7 @@ public class TopDownAnalyzer {
private JetScope getPropertyDeclarationInnerScope(@NotNull JetScope outerScope, @NotNull PropertyDescriptor propertyDescriptor) {
WritableScopeImpl result = new WritableScopeImpl(outerScope, propertyDescriptor, trace.getErrorHandler()).setDebugName("Property declaration inner scope");
for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParemeters()) {
for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) {
result.addTypeParameterDescriptor(typeParameterDescriptor);
}
JetType receiverType = propertyDescriptor.getReceiverType();
@@ -0,0 +1,122 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetType;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author abreslav
*/
/*package*/ class OverloadingConflictResolver {
private final JetSemanticServices semanticServices;
public OverloadingConflictResolver(@NotNull JetSemanticServices semanticServices) {
this.semanticServices = semanticServices;
}
@Nullable
public <Descriptor extends CallableDescriptor> Descriptor findMaximallySpecific(Map<Descriptor, Descriptor> candidates, Map<Descriptor, TemporaryBindingTrace> traces, boolean discriminateGenericDescriptors) {
Map<Descriptor, TemporaryBindingTrace> maximallySpecific = Maps.newHashMap();
meLoop:
for (Map.Entry<Descriptor, Descriptor> myEntry : candidates.entrySet()) {
Descriptor me = myEntry.getValue();
TemporaryBindingTrace myTrace = traces.get(myEntry.getKey());
for (Descriptor other : candidates.values()) {
if (other == me) continue;
if (!moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors)) continue meLoop;
}
maximallySpecific.put(me, myTrace);
}
if (maximallySpecific.size() == 1) {
Map.Entry<Descriptor, TemporaryBindingTrace> result = maximallySpecific.entrySet().iterator().next();
result.getValue().commit();
return result.getKey();
}
return null;
}
/**
* Let < mean "more specific"
* Subtype < supertype
* Double < Float
* Int < Long
* Int < Short < Byte
*/
private <Descriptor extends CallableDescriptor> boolean moreSpecific(Descriptor f, Descriptor g, boolean discriminateGenericDescriptors) {
if (overrides(f, g)) return true;
if (overrides(g, f)) return false;
List<ValueParameterDescriptor> fParams = f.getValueParameters();
List<ValueParameterDescriptor> gParams = g.getValueParameters();
int fSize = fParams.size();
if (fSize != gParams.size()) return false;
for (int i = 0; i < fSize; i++) {
JetType fParamType = fParams.get(i).getOutType();
JetType gParamType = gParams.get(i).getOutType();
if (!semanticServices.getTypeChecker().isSubtypeOf(fParamType, gParamType)
&& !numericTypeMoreSpecific(fParamType, gParamType)
) {
return false;
}
}
if (discriminateGenericDescriptors && isGeneric(f)) {
if (!isGeneric(g)) {
return false;
}
// g is generic, too
return moreSpecific(DescriptorUtils.substituteBounds(f), DescriptorUtils.substituteBounds(g), false);
}
return true;
}
private boolean isGeneric(CallableDescriptor f) {
return !f.getOriginal().getTypeParameters().isEmpty();
}
private boolean numericTypeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) {
JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary();
JetType _double = standardLibrary.getDoubleType();
JetType _float = standardLibrary.getFloatType();
JetType _long = standardLibrary.getLongType();
JetType _int = standardLibrary.getIntType();
JetType _byte = standardLibrary.getByteType();
JetType _short = standardLibrary.getShortType();
if (semanticServices.getTypeChecker().equalTypes(specific, _double) && semanticServices.getTypeChecker().equalTypes(general, _float)) return true;
if (semanticServices.getTypeChecker().equalTypes(specific, _int)) {
if (semanticServices.getTypeChecker().equalTypes(general, _long)) return true;
if (semanticServices.getTypeChecker().equalTypes(general, _byte)) return true;
if (semanticServices.getTypeChecker().equalTypes(general, _short)) return true;
}
if (semanticServices.getTypeChecker().equalTypes(specific, _short) && semanticServices.getTypeChecker().equalTypes(general, _byte)) return true;
return false;
}
private <Descriptor extends CallableDescriptor> boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) {
Set<? extends CallableDescriptor> overriddenDescriptors = f.getOriginal().getOverriddenDescriptors();
CallableDescriptor originalG = g.getOriginal();
for (CallableDescriptor overriddenFunction : overriddenDescriptors) {
if (originalG.equals(overriddenFunction.getOriginal())) return true;
}
return false;
}
}
@@ -0,0 +1,71 @@
package org.jetbrains.jet.lang.resolve.calls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetTypeProjection;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collection;
import java.util.List;
/**
* @author abreslav
*/
/*package*/ class ResolutionTask<Descriptor extends CallableDescriptor> {
private final Collection<Descriptor> candidates;
private final JetType receiverType;
private final List<JetTypeProjection> typeArguments;
private final List<? extends ValueArgument> valueArguments;
private final List<JetExpression> functionLiteralArguments;
public ResolutionTask(
@NotNull Collection<Descriptor> candidates,
@Nullable JetType receiverType,
@NotNull List<JetTypeProjection> typeArguments,
@NotNull List<? extends ValueArgument> valueArguments,
@NotNull List<JetExpression> functionLiteralArguments) {
this.candidates = candidates;
this.receiverType = receiverType;
this.typeArguments = typeArguments;
this.valueArguments = valueArguments;
this.functionLiteralArguments = functionLiteralArguments;
}
public ResolutionTask(
@NotNull Collection<Descriptor> candidates,
@Nullable JetType receiverType,
@NotNull Call call
) {
this(candidates, receiverType, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments());
}
@NotNull
public Collection<Descriptor> getCandidates() {
return candidates;
}
@Nullable
public JetType getReceiverType() {
return receiverType;
}
@NotNull
public List<JetTypeProjection> getTypeArguments() {
return typeArguments;
}
@NotNull
public List<? extends ValueArgument> getValueArguments() {
return valueArguments;
}
@NotNull
public List<JetExpression> getFunctionLiteralArguments() {
return functionLiteralArguments;
}
}
@@ -0,0 +1,108 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collection;
import java.util.List;
/**
* @author abreslav
*/
/*package*/ abstract class TaskPrioritizer<Descriptor extends CallableDescriptor> {
public static <T extends DeclarationDescriptor> void splitLexicallyLocalDescriptors(
Collection<? extends T> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, List<? super T> local, List<? super T> nonlocal) {
for (T descriptor : allDescriptors) {
if (isLocal(containerOfTheCurrentLocality, descriptor)) {
local.add(descriptor);
}
else {
nonlocal.add(descriptor);
}
}
}
/**
* The primary case for local extensions is the following:
*
* I had a locally declared extension function or a local variable of function type called foo
* And I called it on my x
* Now, someone added function foo() to the class of x
* My code should not change
*
* thus
*
* local extension prevail over members (and members prevail over all non-local extensions)
*/
public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
DeclarationDescriptor parent = candidate.getContainingDeclaration();
if (!(parent instanceof FunctionDescriptor)) {
return false;
}
FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent;
DeclarationDescriptor current = containerOfTheCurrentLocality;
while (current != null) {
if (current == functionDescriptor) {
return true;
}
current = current.getContainingDeclaration();
}
return false;
}
public List<ResolutionTask<Descriptor>> computePrioritizedTasks(JetScope scope, JetType receiverType, Call call, String name) {
List<ResolutionTask<Descriptor>> result = Lists.newArrayList();
if (receiverType != null) {
Collection<Descriptor> extensionFunctions = getExtensionsByName(scope, name);
List<Descriptor> nonlocals = Lists.newArrayList();
List<Descriptor> locals = Lists.newArrayList();
splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals);
Collection<Descriptor> members = getMembersByName(receiverType, name);
addTask(result, receiverType, call, locals);
addTask(result, null, call, members);
addTask(result, receiverType, call, nonlocals);
}
else {
Collection<Descriptor> functions = getNonExtensionsByName(scope, name);
List<Descriptor> nonlocals = Lists.newArrayList();
List<Descriptor> locals = Lists.newArrayList();
splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals);
addTask(result, receiverType, call, locals);
addTask(result, receiverType, call, nonlocals);
}
return result;
}
@NotNull
protected abstract Collection<Descriptor> getNonExtensionsByName(JetScope scope, String name);
@NotNull
protected abstract Collection<Descriptor> getMembersByName(@NotNull JetType receiverType, String name);
@NotNull
protected abstract Collection<Descriptor> getExtensionsByName(JetScope scope, String name);
private void addTask(@NotNull List<ResolutionTask<Descriptor>> result, @Nullable JetType receiverType, @NotNull Call call, @NotNull Collection<Descriptor> candidates) {
if (candidates.isEmpty()) return;
result.add(createTask(receiverType, call, candidates));
}
@NotNull
protected abstract ResolutionTask<Descriptor> createTask(JetType receiverType, Call call, Collection<Descriptor> candidates);
}
@@ -0,0 +1,22 @@
package org.jetbrains.jet.lang.resolve.calls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.resolve.BindingTrace;
/**
* @author abreslav
*/
/*package*/ interface TracingStrategy {
void bindReference(@NotNull BindingTrace trace, @NotNull CallableDescriptor descriptor);
void reportOverallResolutionError(@NotNull BindingTrace trace, @NotNull String message);
void reportWrongTypeArguments(@NotNull BindingTrace trace, @NotNull String message);
void reportWrongValueArguments(@NotNull BindingTrace trace, @NotNull String message);
void reportUnresolvedReference(@NotNull BindingTrace trace);
void reportErrorOnReference(BindingTrace trace, String message);
}
@@ -0,0 +1,154 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.psi.JetLabelQualifiedExpression;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.types.CallMaker;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
/**
* @author abreslav
*/
/*package*/ class ValueArgumentsToParametersMapper {
public static <Descriptor extends CallableDescriptor> boolean mapValueArgumentsToParameters(
@NotNull ResolutionTask<Descriptor> task,
@NotNull TracingStrategy tracing,
@NotNull Descriptor candidate,
@NotNull BindingTrace temporaryTrace,
@NotNull Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters
) {
Set<ValueParameterDescriptor> usedParameters = Sets.newHashSet();
List<ValueParameterDescriptor> valueParameters = candidate.getValueParameters();
Map<String, ValueParameterDescriptor> parameterByName = Maps.newHashMap();
for (ValueParameterDescriptor valueParameter : valueParameters) {
parameterByName.put(valueParameter.getName(), valueParameter);
}
List<? extends ValueArgument> valueArguments = task.getValueArguments();
boolean error = false;
boolean someNamed = false;
boolean somePositioned = false;
for (int i = 0; i < valueArguments.size(); i++) {
ValueArgument valueArgument = valueArguments.get(i);
if (valueArgument.isNamed()) {
someNamed = true;
ASTNode nameNode = valueArgument.getArgumentName().getNode();
if (somePositioned) {
temporaryTrace.getErrorHandler().genericError(nameNode, "Mixing named and positioned arguments in not allowed");
error = true;
}
else {
ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(valueArgument.getArgumentName().getReferenceExpression().getReferencedName());
if (!usedParameters.add(valueParameterDescriptor)) {
temporaryTrace.getErrorHandler().genericError(nameNode, "An argument is already passed for this parameter");
}
if (valueParameterDescriptor == null) {
temporaryTrace.getErrorHandler().genericError(nameNode, "Cannot find a parameter with this name");
error = true;
}
else {
temporaryTrace.record(REFERENCE_TARGET, valueArgument.getArgumentName().getReferenceExpression(), valueParameterDescriptor);
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
}
}
}
else {
somePositioned = true;
if (someNamed) {
temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Mixing named and positioned arguments in not allowed");
error = true;
}
else {
int parameterCount = valueParameters.size();
if (i < parameterCount) {
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i);
usedParameters.add(valueParameterDescriptor);
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
}
else if (!valueParameters.isEmpty()) {
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (valueParameterDescriptor.isVararg()) {
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
usedParameters.add(valueParameterDescriptor);
}
else {
temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Too many arguments");
error = true;
}
}
else {
temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Too many arguments");
error = true;
}
}
}
}
List<JetExpression> functionLiteralArguments = task.getFunctionLiteralArguments();
if (!functionLiteralArguments.isEmpty()) {
JetExpression possiblyLabeledFunctionLiteral = functionLiteralArguments.get(0);
if (valueParameters.isEmpty()) {
temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Too many arguments");
error = true;
} else {
JetFunctionLiteralExpression functionLiteral;
if (possiblyLabeledFunctionLiteral instanceof JetLabelQualifiedExpression) {
JetLabelQualifiedExpression labeledFunctionLiteral = (JetLabelQualifiedExpression) possiblyLabeledFunctionLiteral;
functionLiteral = (JetFunctionLiteralExpression) labeledFunctionLiteral.getLabeledExpression();
}
else {
functionLiteral = (JetFunctionLiteralExpression) possiblyLabeledFunctionLiteral;
}
ValueParameterDescriptor parameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (parameterDescriptor.isVararg()) {
temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list");
error = true;
}
else {
if (!usedParameters.add(parameterDescriptor)) {
temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Too many arguments");
error = true;
}
else {
argumentsToParameters.put(CallMaker.makeValueArgument(functionLiteral), parameterDescriptor);
}
}
}
for (int i = 1; i < functionLiteralArguments.size(); i++) {
JetExpression argument = functionLiteralArguments.get(i);
temporaryTrace.getErrorHandler().genericError(argument.getNode(), "Only one function literal is allowed outside a parenthesized argument list");
error = true;
}
}
for (ValueParameterDescriptor valueParameter : valueParameters) {
if (!usedParameters.contains(valueParameter)) {
if (!valueParameter.hasDefaultValue()) {
tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName());
error = true;
}
}
}
return error;
}
}
@@ -17,8 +17,8 @@ public class CallMaker {
private static class ExpressionValueArgument implements ValueArgument {
private final JetExpression expression;
private final PsiElement reportErrorsOn;
private final PsiElement reportErrorsOn;
private ExpressionValueArgument(@NotNull JetExpression expression) {
this(expression, expression);
}
@@ -58,14 +58,14 @@ public class CallMaker {
public PsiElement asElement() {
return reportErrorsOn;
}
}
}
private static abstract class CallStub implements Call {
@Override
public JetValueArgumentList getValueArgumentList() {
return null;
}
@NotNull
@Override
public List<JetExpression> getFunctionLiteralArguments() {
@@ -82,8 +82,8 @@ public class CallMaker {
public JetTypeArgumentList getTypeArgumentList() {
return null;
}
}
}
public static Call makeCallWithArguments(final JetExpression calleeExpression, final List<? extends ValueArgument> valueArguments) {
return new CallStub() {
@Override
@@ -128,4 +128,8 @@ public class CallMaker {
public static ValueArgument makeValueArgument(@Nullable JetExpression expression, @NotNull PsiElement reportErrorsOn) {
return new ExpressionValueArgument(expression, reportErrorsOn);
}
public static Call makePropertyCall(@NotNull JetSimpleNameExpression nameExpression) {
return makeCall(nameExpression, Collections.<JetExpression>emptyList());
}
}
@@ -181,7 +181,7 @@ public class ErrorUtils {
isError(type.getConstructor()));
}
public static boolean isError(@NotNull FunctionDescriptor candidate) {
public static boolean isError(@NotNull DeclarationDescriptor candidate) {
return candidate.getContainingDeclaration() == getErrorClass();
}
@@ -334,6 +334,10 @@ public class JetTypeChecker {
return new TypeCheckingProcedure().run(subtype, supertype);
}
public boolean equalTypes(@NotNull JetType a, @NotNull JetType b) {
return isSubtypeOf(a, b) && isSubtypeOf(b, a);
}
private static class OldProcedure {
public static boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) {
@@ -593,7 +597,5 @@ public class JetTypeChecker {
protected Boolean result() {
return result;
}
}
}
@@ -18,6 +18,7 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
import org.jetbrains.jet.lang.resolve.constants.ErrorValue;
@@ -662,7 +663,7 @@ public class JetTypeInferrer {
try {
result = expression.visit(this, context);
// Some recursive definitions (object expressions) must put their types in the cache manually:
if ((boolean) context.trace.get(BindingContext.PROCESSED, expression)) {
if (context.trace.get(BindingContext.PROCESSED, expression)) {
return context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
}
@@ -730,41 +731,70 @@ public class JetTypeInferrer {
}
}
else {
assert JetTokens.IDENTIFIER == expression.getReferencedNameElementType();
if (referencedName != null) {
VariableDescriptor variable = context.scope.getVariable(referencedName);
if (variable != null) {
context.trace.record(REFERENCE_TARGET, expression, variable);
JetType result = variable.getOutType();
if (result == null) {
context.trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context");
}
return context.services.checkEnrichedType(result, expression, context);
}
else {
ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
if (classifier != null) {
JetType classObjectType = classifier.getClassObjectType();
JetType result = null;
if (classObjectType != null && (isNamespacePosition() || classifier.isClassObjectAValue())) {
result = classObjectType;
}
else {
context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object");
}
context.trace.record(REFERENCE_TARGET, expression, classifier);
return context.services.checkEnrichedType(result, expression, context);
}
else {
JetType[] result = new JetType[1];
if (furtherNameLookup(expression, referencedName, result, context)) {
return context.services.checkEnrichedType(result[0], expression, context);
}
}
}
context.trace.getErrorHandler().unresolvedReference(expression);
return getSelectorReturnType(null, expression, context); // TODO : Extensions to this
// assert JetTokens.IDENTIFIER == expression.getReferencedNameElementType();
// if (referencedName != null) {
// VariableDescriptor variable = context.scope.getVariable(referencedName);
// if (variable != null) {
// context.trace.record(REFERENCE_TARGET, expression, variable);
// JetType result = variable.getOutType();
// if (result == null) {
// context.trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context");
// }
// return context.services.checkEnrichedType(result, expression, context);
// }
// else {
// return lookupNamespaceOrClassObject(expression, referencedName, context);
// ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
// if (classifier != null) {
// JetType classObjectType = classifier.getClassObjectType();
// JetType result = null;
// if (classObjectType != null && (isNamespacePosition() || classifier.isClassObjectAValue())) {
// result = classObjectType;
// }
// else {
// context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object");
// }
// context.trace.record(REFERENCE_TARGET, expression, classifier);
// return context.services.checkEnrichedType(result, expression, context);
// }
// else {
// JetType[] result = new JetType[1];
// if (furtherNameLookup(expression, referencedName, result, context)) {
// return context.services.checkEnrichedType(result[0], expression, context);
// }
//
// }
// }
// context.trace.getErrorHandler().unresolvedReference(expression);
// }
}
return null;
}
private JetType lookupNamespaceOrClassObject(JetSimpleNameExpression expression, String referencedName, TypeInferenceContext context) {
ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
if (classifier != null) {
JetType classObjectType = classifier.getClassObjectType();
JetType result = null;
if (classObjectType != null && (isNamespacePosition() || classifier.isClassObjectAValue())) {
result = classObjectType;
}
else {
context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object");
}
context.trace.record(REFERENCE_TARGET, expression, classifier);
if (result == null) {
return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName());
}
return context.services.checkEnrichedType(result, expression, context);
}
else {
JetType[] result = new JetType[1];
if (furtherNameLookup(expression, referencedName, result, context)) {
return context.services.checkEnrichedType(result[0], expression, context);
}
}
return null;
}
@@ -1945,11 +1975,25 @@ public class JetTypeInferrer {
@Nullable
private JetType getSelectorReturnType(@Nullable JetType receiverType, @NotNull JetExpression selectorExpression, @NotNull TypeInferenceContext context) {
if (selectorExpression instanceof JetCallExpression) {
return context.services.callResolver.resolveCall(context.scope, receiverType, (JetCallExpression) selectorExpression, context.expectedType);
return context.services.callResolver.resolveCall(context.trace, context.scope, receiverType, (JetCallExpression) selectorExpression, context.expectedType);
}
else if (selectorExpression instanceof JetSimpleNameExpression) {
JetScope scope = receiverType != null ? receiverType.getMemberScope() : context.scope;
return getType(selectorExpression, context.replaceScope(scope));
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) selectorExpression;
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
VariableDescriptor variableDescriptor = context.services.callResolver.resolveSimpleProperty(temporaryTrace, context.scope, receiverType, nameExpression, context.expectedType);
if (variableDescriptor != null) {
temporaryTrace.commit();
return context.services.checkEnrichedType(variableDescriptor.getOutType(), nameExpression, context);
}
TypeInferenceContext newContext = receiverType == null ? context : context.replaceScope(receiverType.getMemberScope());
JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedName(), newContext);
if (jetType == null) {
context.trace.getErrorHandler().unresolvedReference(nameExpression);
}
return context.services.checkEnrichedType(jetType, nameExpression, context);
// JetScope scope = receiverType != null ? receiverType.getMemberScope() : context.scope;
// return getType(selectorExpression, context.replaceScope(scope));
}
else if (selectorExpression instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
@@ -1968,7 +2012,7 @@ public class JetTypeInferrer {
@Override
public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) {
JetType expressionType = context.services.callResolver.resolveCall(context.scope, null, expression, context.expectedType);
JetType expressionType = context.services.callResolver.resolveCall(context.trace, context.scope, null, expression, context.expectedType);
return context.services.checkType(expressionType, expression, context);
}
@@ -2005,6 +2049,7 @@ public class JetTypeInferrer {
if (receiverType == null) return null;
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
context.trace,
context.scope,
CallMaker.makeCall(expression),
expression.getOperationSign(),
@@ -2159,6 +2204,7 @@ public class JetTypeInferrer {
String name = "contains";
JetType receiverType = context.services.safeGetType(context.scope, right, NO_EXPECTED_TYPE);
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
context.trace,
context.scope,
CallMaker.makeCall(operationSign, Collections.singletonList(left)),
operationSign,
@@ -2226,6 +2272,7 @@ public class JetTypeInferrer {
if (receiverType != null) {
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
context.trace,
context.scope,
CallMaker.makeCall(expression, expression.getIndexExpressions()),
expression,
@@ -2243,6 +2290,7 @@ public class JetTypeInferrer {
protected JetType getTypeForBinaryCall(JetScope scope, String name, TypeInferenceContext context, JetBinaryExpression binaryExpression) {
JetType leftType = getType(binaryExpression.getLeft(), context.replaceScope(scope));
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
context.trace,
scope,
CallMaker.makeCall(binaryExpression),
binaryExpression.getOperationReference(),
@@ -2479,10 +2527,11 @@ public class JetTypeInferrer {
// arrayAccessExpression,
// "set", arrayAccessExpression.getArrayExpression(), NO_EXPECTED_TYPE);
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
scope,
call,
arrayAccessExpression,
"set", receiverType, NO_EXPECTED_TYPE);
context.trace,
scope,
call,
arrayAccessExpression,
"set", receiverType, NO_EXPECTED_TYPE);
if (functionDescriptor == null) return null;
context.trace.record(REFERENCE_TARGET, operationSign, functionDescriptor);
return context.services.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
@@ -64,7 +64,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, jetFunction);
if (functionDescriptor == null) return null;
final Set<? extends FunctionDescriptor> overriddenFunctions = functionDescriptor.getOverriddenFunctions();
final Set<? extends FunctionDescriptor> overriddenFunctions = functionDescriptor.getOverriddenDescriptors();
Icon icon = isMember(functionDescriptor) ? (overriddenFunctions.isEmpty() ? PlatformIcons.METHOD_ICON : OVERRIDING_FUNCTION) : PlatformIcons.FUNCTION_ICON;
return new LineMarkerInfo<JetNamedFunction>(
jetFunction, jetFunction.getTextOffset(), icon, Pass.UPDATE_ALL,
@@ -171,7 +171,7 @@ public class DescriptorRenderer {
@Override
public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) {
String typeString = renderPropertyPrefixAndComputeTypeString(
builder, descriptor.getTypeParemeters(),
builder, descriptor.getTypeParameters(),
descriptor.getReceiverType(),
descriptor.getOutType(),
descriptor.getInType());