diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 75828034da4..09d63727589 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -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 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 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 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 diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java index 81230352807..3e9412bf690 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java @@ -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 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; + } } } diff --git a/compiler/testData/diagnostics/tests/Super.kt b/compiler/testData/diagnostics/tests/Super.kt index 3aeca7d9493..f8048612083 100644 --- a/compiler/testData/diagnostics/tests/Super.kt +++ b/compiler/testData/diagnostics/tests/Super.kt @@ -56,8 +56,8 @@ class A() : C(), T { fun foo() { super - super.foo() - super.foo() + super.foo() + super.foo() } trait G {