Drop traits with required classes

#KT-4771 Rejected
This commit is contained in:
Alexander Udalov
2015-06-16 23:40:25 +03:00
parent dc909ba1d4
commit 1a3209e1dc
63 changed files with 49 additions and 1109 deletions
@@ -16,17 +16,17 @@
package org.jetbrains.kotlin.cfg.pseudocode.instructions.eval
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValueFactory
import org.jetbrains.kotlin.cfg.pseudocode.instructions.LexicalScope
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionWithNext
import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionWithNext
import org.jetbrains.kotlin.cfg.pseudocode.instructions.LexicalScope
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
public abstract class OperationInstruction protected constructor(
element: JetElement,
@@ -53,11 +53,6 @@ public abstract class OperationInstruction protected constructor(
}
}
trait StrictlyValuedOperationInstruction: OperationInstruction {
override val outputValue: PseudoValue
get() = resultValue!!
}
public class CallInstruction private constructor(
element: JetElement,
lexicalScope: LexicalScope,
@@ -103,9 +98,12 @@ public class MagicInstruction(
inputValues: List<PseudoValue>,
val expectedTypes: Map<PseudoValue, TypePredicate>,
val kind: MagicKind
) : OperationInstruction(element, lexicalScope, inputValues), StrictlyValuedOperationInstruction {
) : OperationInstruction(element, lexicalScope, inputValues) {
public val synthetic: Boolean get() = outputValue.element == null
override val outputValue: PseudoValue
get() = resultValue!!
override fun accept(visitor: InstructionVisitor) = visitor.visitMagic(this)
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitMagic(this)
@@ -156,7 +154,10 @@ class MergeInstruction private constructor(
element: JetElement,
lexicalScope: LexicalScope,
inputValues: List<PseudoValue>
): OperationInstruction(element, lexicalScope, inputValues), StrictlyValuedOperationInstruction {
): OperationInstruction(element, lexicalScope, inputValues) {
override val outputValue: PseudoValue
get() = resultValue!!
override fun accept(visitor: InstructionVisitor) = visitor.visitMerge(this)
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitMerge(this)
@@ -192,10 +192,7 @@ public interface Errors {
DiagnosticFactory0<JetDelegatorByExpressionSpecifier> DELEGATION_IN_TRAIT = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> TRAIT_WITH_SUPERCLASS = DiagnosticFactory0.create(WARNING);
DiagnosticFactory2<JetNamedDeclaration, ClassDescriptor, ClassDescriptor> UNMET_TRAIT_REQUIREMENT =
DiagnosticFactory2.create(ERROR, PositioningStrategies.DECLARATION_NAME);
DiagnosticFactory0<PsiElement> TRAIT_WITH_SUPERCLASS = DiagnosticFactory0.create(ERROR);
// Enum-specific
@@ -296,7 +296,6 @@ public class DefaultErrorMessages {
MAP.put(DELEGATION_IN_TRAIT, "Interfaces cannot use delegation");
MAP.put(DELEGATION_NOT_TO_TRAIT, "Only interfaces can be delegated to");
MAP.put(DEPRECATED_TRAIT_KEYWORD, "'trait' keyword is deprecated, use 'interface' instead");
MAP.put(UNMET_TRAIT_REQUIREMENT, "Super interface ''{0}'' requires subclasses to extend ''{1}''", NAME, NAME);
MAP.put(NO_CONSTRUCTOR, "This class does not have a constructor");
MAP.put(NOT_A_CLASS, "Not a class");
MAP.put(ILLEGAL_ESCAPE_SEQUENCE, "Illegal escape sequence");
@@ -428,7 +427,7 @@ public class DefaultErrorMessages {
MAP.put(SUPERTYPE_INITIALIZED_IN_TRAIT, "Interfaces cannot initialize supertypes");
MAP.put(CLASS_IN_SUPERTYPE_FOR_ENUM, "Enum class cannot inherit from classes");
MAP.put(CONSTRUCTOR_IN_TRAIT, "An interface may not have a constructor");
MAP.put(TRAIT_WITH_SUPERCLASS, "Specifying a required base class for interface implementations is deprecated");
MAP.put(TRAIT_WITH_SUPERCLASS, "An interface cannot inherit from a class");
MAP.put(SUPERTYPE_APPEARS_TWICE, "A supertype appears twice");
MAP.put(FINAL_SUPERTYPE, "This type is final, so it cannot be inherited from");
MAP.put(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton");
@@ -426,6 +426,8 @@ public class BodyResolver {
JetTypeReference typeReference = entry.getKey();
JetType supertype = entry.getValue();
boolean addSupertype = true;
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) {
if (ErrorUtils.isError(classDescriptor)) continue;
@@ -433,11 +435,14 @@ public class BodyResolver {
if (classDescriptor.getKind() != ClassKind.INTERFACE) {
if (supertypeOwner.getKind() == ClassKind.ENUM_CLASS) {
trace.report(CLASS_IN_SUPERTYPE_FOR_ENUM.on(typeReference));
addSupertype = false;
}
else if (supertypeOwner.getKind() == ClassKind.INTERFACE &&
!classAppeared && !TypesPackage.isDynamic(supertype) /* avoid duplicate diagnostics */) {
trace.report(TRAIT_WITH_SUPERCLASS.on(typeReference));
addSupertype = false;
}
if (classAppeared) {
trace.report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference));
}
@@ -451,7 +456,7 @@ public class BodyResolver {
}
TypeConstructor constructor = supertype.getConstructor();
if (!typeConstructors.add(constructor)) {
if (addSupertype && !typeConstructors.add(constructor)) {
trace.report(SUPERTYPE_APPEARS_TWICE.on(typeReference));
}
@@ -21,16 +21,15 @@ import com.google.common.collect.Multimap
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors.CONSTRUCTOR_IN_OBJECT
import org.jetbrains.kotlin.diagnostics.Errors.CONSTRUCTOR_IN_TRAIT
import org.jetbrains.kotlin.diagnostics.Errors.MANY_COMPANION_OBJECTS
import org.jetbrains.kotlin.diagnostics.Errors.CONSTRUCTOR_IN_OBJECT
import org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.lazy.*
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.resolve.resolveUtil.checkTraitRequirements
import org.jetbrains.kotlin.resolve.varianceChecker.VarianceChecker
import java.util.ArrayList
import javax.inject.Inject
@@ -244,8 +243,6 @@ public class LazyTopDownAnalyzer {
declarationResolver!!.checkRedeclarationsInPackages(topLevelDescriptorProvider!!, topLevelFqNames)
declarationResolver!!.checkRedeclarations(c)
checkTraitRequirements(c.getDeclaredClasses(), trace!!)
overrideResolver!!.check(c)
varianceChecker!!.check(c)
@@ -1,62 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.resolveUtil
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
fun checkTraitRequirements(c: Map<JetClassOrObject, ClassDescriptorWithResolutionScopes>, trace: BindingTrace) {
for ((classOrObject, descriptor) in c.entrySet()) {
if (DescriptorUtils.isTrait(descriptor)) continue
val satisfiedRequirements = getSuperClassesReachableByClassInheritance(descriptor)
for (superTrait in getAllSuperTraits(descriptor)) {
for (traitSupertype in superTrait.getDefaultType().getConstructor().getSupertypes()) {
val traitSuperClass = traitSupertype.getConstructor().getDeclarationDescriptor()
if (DescriptorUtils.isClass(traitSuperClass) && traitSuperClass !in satisfiedRequirements) {
trace.report(Errors.UNMET_TRAIT_REQUIREMENT.on(classOrObject, superTrait, traitSuperClass as ClassDescriptor))
}
}
}
}
}
private fun getAllSuperTraits(descriptor: ClassDescriptor): List<ClassDescriptor> {
@suppress("UNCHECKED_CAST")
return TypeUtils.getAllSupertypes(descriptor.getDefaultType())
.map { supertype -> supertype.getConstructor().getDeclarationDescriptor() }
.filter { superClass -> DescriptorUtils.isTrait(superClass) } as List<ClassDescriptor>
}
private fun getSuperClassesReachableByClassInheritance(
descriptor: ClassDescriptor,
result: MutableSet<ClassDescriptor> = hashSetOf()
): Set<ClassDescriptor> {
val superClass = descriptor.getSuperClassOrAny()
result.add(superClass)
if (!KotlinBuiltIns.isAny(superClass)) {
getSuperClassesReachableByClassInheritance(superClass, result)
}
return result
}