Fixing super in a package-level function

This commit is contained in:
Andrey Breslav
2012-11-01 18:12:47 +04:00
parent ce9c302fe1
commit a0cd26960a
3 changed files with 166 additions and 99 deletions
@@ -50,6 +50,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
@@ -395,16 +396,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetTypeInfo visitThisExpression(JetThisExpression expression, ExpressionTypingContext context) {
JetType result = null;
ReceiverParameterDescriptor thisReceiver = resolveToReceiver(expression, context, false);
LabelResolver.LabeledReceiverResolutionResult resolutionResult = resolveToReceiver(expression, context, false);
if (thisReceiver != null) {
if (!thisReceiver.exists()) {
switch (resolutionResult.getCode()) {
case LABEL_RESOLUTION_ERROR:
// Do nothing, the error is already reported
break;
case NO_THIS:
context.trace.report(NO_THIS.on(expression));
}
else {
result = thisReceiver.getType();
break;
case SUCCESS:
result = resolutionResult.getReceiverParameterDescriptor().getType();
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
}
break;
}
return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo);
}
@@ -415,118 +419,134 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(SUPER_IS_NOT_AN_EXPRESSION.on(expression, expression.getText()));
return JetTypeInfo.create(null, context.dataFlowInfo);
}
JetType result = null;
ReceiverParameterDescriptor thisReceiver = resolveToReceiver(expression, context, true);
if (thisReceiver == null) return JetTypeInfo.create(null, context.dataFlowInfo);
if (!thisReceiver.exists()) {
context.trace.report(SUPER_NOT_AVAILABLE.on(expression));
LabelResolver.LabeledReceiverResolutionResult resolutionResult = resolveToReceiver(expression, context, true);
switch (resolutionResult.getCode()) {
case LABEL_RESOLUTION_ERROR:
// The error is already reported
return JetTypeInfo.create(null, context.dataFlowInfo);
case NO_THIS:
context.trace.report(SUPER_NOT_AVAILABLE.on(expression));
return JetTypeInfo.create(null, context.dataFlowInfo);
case SUCCESS:
JetType result = checkPossiblyQualifiedSuper(expression, context, resolutionResult.getReceiverParameterDescriptor());
if (result != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
}
return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo);
}
else {
JetType thisType = thisReceiver.getType();
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
TypeSubstitutor substitutor = TypeSubstitutor.create(thisType);
throw new IllegalStateException("Unknown code: " + resolutionResult.getCode());
}
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
JetTypeElement typeElement = superTypeQualifier.getTypeElement();
private JetType checkPossiblyQualifiedSuper(
JetSuperExpression expression,
ExpressionTypingContext context,
ReceiverParameterDescriptor thisReceiver
) {
JetType result = null;
JetType thisType = thisReceiver.getType();
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
TypeSubstitutor substitutor = TypeSubstitutor.create(thisType);
DeclarationDescriptor classifierCandidate = null;
JetType supertype = null;
PsiElement redundantTypeArguments = null;
if (typeElement instanceof JetUserType) {
JetUserType userType = (JetUserType) typeElement;
// This may be just a superclass name even if the superclass is generic
if (userType.getTypeArguments().isEmpty()) {
classifierCandidate = context.expressionTypingServices.getTypeResolver().resolveClass(context.scope, userType, context.trace);
}
else {
supertype = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, superTypeQualifier, context.trace, true);
redundantTypeArguments = userType.getTypeArgumentList();
}
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
JetTypeElement typeElement = superTypeQualifier.getTypeElement();
DeclarationDescriptor classifierCandidate = null;
JetType supertype = null;
PsiElement redundantTypeArguments = null;
if (typeElement instanceof JetUserType) {
JetUserType userType = (JetUserType) typeElement;
// This may be just a superclass name even if the superclass is generic
if (userType.getTypeArguments().isEmpty()) {
classifierCandidate = context.expressionTypingServices.getTypeResolver().resolveClass(context.scope, userType, context.trace);
}
else {
supertype = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, superTypeQualifier, context.trace, true);
}
if (supertype != null) {
if (supertypes.contains(supertype)) {
result = supertype;
}
}
else if (classifierCandidate instanceof ClassDescriptor) {
ClassDescriptor superclass = (ClassDescriptor) classifierCandidate;
for (JetType declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result = substitutor.safeSubstitute(declaredSupertype, Variance.INVARIANT);
break;
}
}
}
boolean validClassifier = classifierCandidate != null && !ErrorUtils.isError(classifierCandidate);
boolean validType = supertype != null && !ErrorUtils.isErrorType(supertype);
if (result == null && (validClassifier || validType)) {
context.trace.report(NOT_A_SUPERTYPE.on(superTypeQualifier));
}
else if (redundantTypeArguments != null) {
context.trace.report(TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER.on(redundantTypeArguments));
redundantTypeArguments = userType.getTypeArgumentList();
}
}
else {
if (supertypes.size() > 1) {
context.trace.report(AMBIGUOUS_SUPER.on(expression));
}
else {
// supertypes may be empty when all the supertypes are error types (are not resolved, for example)
JetType type = supertypes.isEmpty()
? KotlinBuiltIns.getInstance().getAnyType()
: supertypes.iterator().next();
result = substitutor.substitute(type, Variance.INVARIANT);
}
supertype = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, superTypeQualifier, context.trace, true);
}
if (result != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
context.trace.record(BindingContext.REFERENCE_TARGET, expression.getInstanceReference(), result.getConstructor().getDeclarationDescriptor());
if (superTypeQualifier != null) {
context.trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, superTypeQualifier, context.scope);
}
}
}
return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo);
}
@Nullable // No class receivers
private ReceiverParameterDescriptor resolveToReceiver(JetLabelQualifiedInstanceExpression expression, ExpressionTypingContext context, boolean onlyClassReceivers) {
ReceiverParameterDescriptor thisReceiver = null;
String labelName = expression.getLabelName();
if (labelName != null) {
thisReceiver = context.labelResolver.resolveThisLabel(
expression.getInstanceReference(), expression.getTargetLabel(), context, thisReceiver, new LabelName(labelName));
if (supertype != null) {
if (supertypes.contains(supertype)) {
result = supertype;
}
}
else if (classifierCandidate instanceof ClassDescriptor) {
ClassDescriptor superclass = (ClassDescriptor) classifierCandidate;
for (JetType declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result = substitutor.safeSubstitute(declaredSupertype, Variance.INVARIANT);
break;
}
}
}
boolean validClassifier = classifierCandidate != null && !ErrorUtils.isError(classifierCandidate);
boolean validType = supertype != null && !ErrorUtils.isErrorType(supertype);
if (result == null && (validClassifier || validType)) {
context.trace.report(NOT_A_SUPERTYPE.on(superTypeQualifier));
}
else if (redundantTypeArguments != null) {
context.trace.report(TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER.on(redundantTypeArguments));
}
}
else {
if (supertypes.size() > 1) {
context.trace.report(AMBIGUOUS_SUPER.on(expression));
}
else {
// supertypes may be empty when all the supertypes are error types (are not resolved, for example)
JetType type = supertypes.isEmpty()
? KotlinBuiltIns.getInstance().getAnyType()
: supertypes.iterator().next();
result = substitutor.substitute(type, Variance.INVARIANT);
}
}
if (result != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
context.trace.record(BindingContext.REFERENCE_TARGET, expression.getInstanceReference(), result.getConstructor().getDeclarationDescriptor());
if (superTypeQualifier != null) {
context.trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, superTypeQualifier, context.scope);
}
}
return result;
}
@NotNull // No class receivers
private LabelResolver.LabeledReceiverResolutionResult resolveToReceiver(
JetLabelQualifiedInstanceExpression expression,
ExpressionTypingContext context,
boolean onlyClassReceivers
) {
String labelName = expression.getLabelName();
if (labelName != null) {
return context.labelResolver.resolveThisLabel(expression.getInstanceReference(), expression.getTargetLabel(),
context, new LabelName(labelName));
}
else {
ReceiverParameterDescriptor result = NO_RECEIVER_PARAMETER;
List<ReceiverParameterDescriptor> receivers = context.scope.getImplicitReceiversHierarchy();
if (onlyClassReceivers) {
for (ReceiverParameterDescriptor receiver : receivers) {
if (receiver.getContainingDeclaration() instanceof ClassDescriptor) {
thisReceiver = receiver;
result = receiver;
break;
}
}
}
else if (!receivers.isEmpty()) {
thisReceiver = receivers.get(0);
result = receivers.get(0);
}
else {
thisReceiver = ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
}
if (thisReceiver != null && thisReceiver.exists()) {
context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), thisReceiver.getContainingDeclaration());
if (result.exists()) {
context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), result.getContainingDeclaration());
}
return LabelResolver.LabeledReceiverResolutionResult.labelResolutionSuccess(result);
}
return thisReceiver;
}
@Override
@@ -124,13 +124,14 @@ public class LabelResolver {
return result;
}
public ReceiverParameterDescriptor resolveThisLabel(JetReferenceExpression thisReference, JetSimpleNameExpression targetLabel,
ExpressionTypingContext context, ReceiverParameterDescriptor thisReceiver, LabelName labelName) {
public LabeledReceiverResolutionResult resolveThisLabel(JetReferenceExpression thisReference, JetSimpleNameExpression targetLabel,
ExpressionTypingContext context, LabelName labelName) {
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
int size = declarationsByLabel.size();
assert targetLabel != null;
if (size == 1) {
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
ReceiverParameterDescriptor thisReceiver;
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
thisReceiver = classDescriptor.getThisAsReceiverParameter();
@@ -146,17 +147,20 @@ public class LabelResolver {
assert element != null : "No PSI element for descriptor: " + declarationDescriptor;
context.trace.record(LABEL_TARGET, targetLabel, element);
context.trace.record(REFERENCE_TARGET, thisReference, declarationDescriptor);
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver);
}
else if (size == 0) {
JetElement element = resolveNamedLabel(labelName, targetLabel, false, context);
if (element instanceof JetFunctionLiteralExpression) {
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
if (declarationDescriptor instanceof FunctionDescriptor) {
thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiverParameter();
ReceiverParameterDescriptor thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiverParameter();
if (thisReceiver.exists()) {
context.trace.record(LABEL_TARGET, targetLabel, element);
context.trace.record(REFERENCE_TARGET, thisReference, declarationDescriptor);
}
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver);
}
else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
@@ -169,6 +173,49 @@ public class LabelResolver {
else {
context.trace.report(AMBIGUOUS_LABEL.on(targetLabel));
}
return thisReceiver;
return LabeledReceiverResolutionResult.labelResolutionFailed();
}
public static final class LabeledReceiverResolutionResult {
public static LabeledReceiverResolutionResult labelResolutionSuccess(@NotNull ReceiverParameterDescriptor receiverParameterDescriptor) {
if (!receiverParameterDescriptor.exists()) {
return new LabeledReceiverResolutionResult(Code.NO_THIS, null);
}
return new LabeledReceiverResolutionResult(Code.SUCCESS, receiverParameterDescriptor);
}
public static LabeledReceiverResolutionResult labelResolutionFailed() {
return new LabeledReceiverResolutionResult(Code.LABEL_RESOLUTION_ERROR, null);
}
public enum Code {
LABEL_RESOLUTION_ERROR,
NO_THIS,
SUCCESS
}
private final Code code;
private final ReceiverParameterDescriptor receiverParameterDescriptor;
private LabeledReceiverResolutionResult(
Code code,
ReceiverParameterDescriptor receiverParameterDescriptor
) {
this.code = code;
this.receiverParameterDescriptor = receiverParameterDescriptor;
}
public Code getCode() {
return code;
}
public boolean success() {
return code == Code.SUCCESS;
}
public ReceiverParameterDescriptor getReceiverParameterDescriptor() {
assert success() : "Don't try to obtain the receiver when resolution failed with " + code;
return receiverParameterDescriptor;
}
}
}
+2 -2
View File
@@ -56,8 +56,8 @@ class A<E>() : C(), T {
fun foo() {
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>
super.foo()
super<Nothing>.foo()
<!SUPER_NOT_AVAILABLE!>super<!>.foo()
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.foo()
}
trait G<T> {