KT-1041 Add check that thrown/catched expression is of Throwable type
This commit is contained in:
@@ -842,6 +842,8 @@ public class JetTypeMapper {
|
|||||||
knowTypes.put(standardLibrary.getNullableStringType(),JL_STRING_TYPE);
|
knowTypes.put(standardLibrary.getNullableStringType(),JL_STRING_TYPE);
|
||||||
knowTypes.put(standardLibrary.getCharSequenceType(),JL_CHAR_SEQUENCE_TYPE);
|
knowTypes.put(standardLibrary.getCharSequenceType(),JL_CHAR_SEQUENCE_TYPE);
|
||||||
knowTypes.put(standardLibrary.getNullableCharSequenceType(),JL_CHAR_SEQUENCE_TYPE);
|
knowTypes.put(standardLibrary.getNullableCharSequenceType(),JL_CHAR_SEQUENCE_TYPE);
|
||||||
|
knowTypes.put(standardLibrary.getThrowableType(), TYPE_THROWABLE);
|
||||||
|
knowTypes.put(standardLibrary.getNullableThrowableType(), TYPE_THROWABLE);
|
||||||
|
|
||||||
for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
|
for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
|
||||||
PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
|
PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
|
||||||
|
|||||||
+3
-1
@@ -204,10 +204,11 @@ public class JavaTypeTransformer {
|
|||||||
classTypesMap.put("java.lang.Object", JetStandardClasses.getNullableAnyType());
|
classTypesMap.put("java.lang.Object", JetStandardClasses.getNullableAnyType());
|
||||||
classTypesMap.put("java.lang.String", standardLibrary.getNullableStringType());
|
classTypesMap.put("java.lang.String", standardLibrary.getNullableStringType());
|
||||||
classTypesMap.put("java.lang.CharSequence", standardLibrary.getNullableCharSequenceType());
|
classTypesMap.put("java.lang.CharSequence", standardLibrary.getNullableCharSequenceType());
|
||||||
|
classTypesMap.put("java.lang.Throwable", standardLibrary.getThrowableType());
|
||||||
}
|
}
|
||||||
return classTypesMap;
|
return classTypesMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, ClassDescriptor> getPrimitiveWrappersClassDescriptorMap() {
|
public Map<String, ClassDescriptor> getPrimitiveWrappersClassDescriptorMap() {
|
||||||
if (classDescriptorMap == null) {
|
if (classDescriptorMap == null) {
|
||||||
classDescriptorMap = new HashMap<String, ClassDescriptor>();
|
classDescriptorMap = new HashMap<String, ClassDescriptor>();
|
||||||
@@ -217,6 +218,7 @@ public class JavaTypeTransformer {
|
|||||||
}
|
}
|
||||||
classDescriptorMap.put("java.lang.String", standardLibrary.getString());
|
classDescriptorMap.put("java.lang.String", standardLibrary.getString());
|
||||||
classDescriptorMap.put("java.lang.CharSequence", standardLibrary.getCharSequence());
|
classDescriptorMap.put("java.lang.CharSequence", standardLibrary.getCharSequence());
|
||||||
|
classDescriptorMap.put("java.lang.Throwable", standardLibrary.getThrowable());
|
||||||
}
|
}
|
||||||
return classDescriptorMap;
|
return classDescriptorMap;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,3 +59,9 @@ class String() : Comparable<String>, CharSequence {
|
|||||||
|
|
||||||
fun equals(other : Any?) : Boolean
|
fun equals(other : Any?) : Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Throwable(message : String? = null, cause: Throwable? = null) {
|
||||||
|
fun getMessage() : String?
|
||||||
|
fun getCause() : Throwable?
|
||||||
|
fun printStackTrace() : Unit
|
||||||
|
}
|
||||||
@@ -72,14 +72,16 @@ public class JetStandardLibrary {
|
|||||||
private ClassDescriptor iterableClass;
|
private ClassDescriptor iterableClass;
|
||||||
private ClassDescriptor comparableClass;
|
private ClassDescriptor comparableClass;
|
||||||
private ClassDescriptor volatileClass;
|
private ClassDescriptor volatileClass;
|
||||||
|
private ClassDescriptor throwableClass;
|
||||||
|
|
||||||
private JetType stringType;
|
private JetType stringType;
|
||||||
private JetType volatileType;
|
private JetType volatileType;
|
||||||
private JetType nullableStringType;
|
private JetType nullableStringType;
|
||||||
private JetType charSequenceType;
|
private JetType charSequenceType;
|
||||||
private JetType nullableCharSequenceType;
|
private JetType nullableCharSequenceType;
|
||||||
|
|
||||||
private JetType nullableTuple0Type;
|
private JetType nullableTuple0Type;
|
||||||
|
private JetType throwableType;
|
||||||
|
private JetType nullableThrowableType;
|
||||||
|
|
||||||
private JetType tuple0Type;
|
private JetType tuple0Type;
|
||||||
|
|
||||||
@@ -143,6 +145,7 @@ public class JetStandardLibrary {
|
|||||||
this.charSequenceClass = (ClassDescriptor) libraryScope.getClassifier("CharSequence");
|
this.charSequenceClass = (ClassDescriptor) libraryScope.getClassifier("CharSequence");
|
||||||
this.arrayClass = (ClassDescriptor) libraryScope.getClassifier("Array");
|
this.arrayClass = (ClassDescriptor) libraryScope.getClassifier("Array");
|
||||||
this.volatileClass = (ClassDescriptor) libraryScope.getClassifier("volatile");
|
this.volatileClass = (ClassDescriptor) libraryScope.getClassifier("volatile");
|
||||||
|
this.throwableClass = (ClassDescriptor) libraryScope.getClassifier("Throwable");
|
||||||
|
|
||||||
this.iterableClass = (ClassDescriptor) libraryScope.getClassifier("Iterable");
|
this.iterableClass = (ClassDescriptor) libraryScope.getClassifier("Iterable");
|
||||||
this.comparableClass = (ClassDescriptor) libraryScope.getClassifier("Comparable");
|
this.comparableClass = (ClassDescriptor) libraryScope.getClassifier("Comparable");
|
||||||
@@ -153,6 +156,8 @@ public class JetStandardLibrary {
|
|||||||
this.nullableCharSequenceType = TypeUtils.makeNullable(charSequenceType);
|
this.nullableCharSequenceType = TypeUtils.makeNullable(charSequenceType);
|
||||||
this.nullableStringType = TypeUtils.makeNullable(stringType);
|
this.nullableStringType = TypeUtils.makeNullable(stringType);
|
||||||
this.volatileType = new JetTypeImpl(getVolatile());
|
this.volatileType = new JetTypeImpl(getVolatile());
|
||||||
|
this.throwableType = new JetTypeImpl(getThrowable());
|
||||||
|
this.nullableThrowableType = TypeUtils.makeNullable(throwableType);
|
||||||
|
|
||||||
this.tuple0Type = new JetTypeImpl(JetStandardClasses.getTuple(0));
|
this.tuple0Type = new JetTypeImpl(JetStandardClasses.getTuple(0));
|
||||||
this.nullableTuple0Type = TypeUtils.makeNullable(tuple0Type);
|
this.nullableTuple0Type = TypeUtils.makeNullable(tuple0Type);
|
||||||
@@ -270,6 +275,12 @@ public class JetStandardLibrary {
|
|||||||
return comparableClass;
|
return comparableClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public ClassDescriptor getThrowable() {
|
||||||
|
initStdClasses();
|
||||||
|
return throwableClass;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<FunctionDescriptor> getTypeInfoFunctions() {
|
public Set<FunctionDescriptor> getTypeInfoFunctions() {
|
||||||
initStdClasses();
|
initStdClasses();
|
||||||
return typeInfoFunction;
|
return typeInfoFunction;
|
||||||
@@ -393,6 +404,17 @@ public class JetStandardLibrary {
|
|||||||
initStdClasses();
|
initStdClasses();
|
||||||
return nullableCharSequenceType;
|
return nullableCharSequenceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType getThrowableType() {
|
||||||
|
initStdClasses();
|
||||||
|
return throwableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JetType getNullableThrowableType() {
|
||||||
|
initStdClasses();
|
||||||
|
return nullableThrowableType;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetType getNullablePrimitiveJetType(PrimitiveType primitiveType) {
|
public JetType getNullablePrimitiveJetType(PrimitiveType primitiveType) {
|
||||||
|
|||||||
+4
-2
@@ -400,6 +400,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
JetExpression catchBody = catchClause.getCatchBody();
|
JetExpression catchBody = catchClause.getCatchBody();
|
||||||
if (catchParameter != null) {
|
if (catchParameter != null) {
|
||||||
VariableDescriptor variableDescriptor = context.getDescriptorResolver().resolveLocalVariableDescriptor(context.scope.getContainingDeclaration(), context.scope, catchParameter);
|
VariableDescriptor variableDescriptor = context.getDescriptorResolver().resolveLocalVariableDescriptor(context.scope.getContainingDeclaration(), context.scope, catchParameter);
|
||||||
|
JetType throwableType = context.semanticServices.getStandardLibrary().getThrowable().getDefaultType();
|
||||||
|
DataFlowUtils.checkType(variableDescriptor.getOutType(), catchParameter, context.replaceExpectedType(throwableType));
|
||||||
if (catchBody != null) {
|
if (catchBody != null) {
|
||||||
WritableScope catchScope = newWritableScopeImpl(context).setDebugName("Catch scope");
|
WritableScope catchScope = newWritableScopeImpl(context).setDebugName("Catch scope");
|
||||||
catchScope.addVariableDescriptor(variableDescriptor);
|
catchScope.addVariableDescriptor(variableDescriptor);
|
||||||
@@ -433,8 +435,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
public JetType visitThrowExpression(JetThrowExpression expression, ExpressionTypingContext context) {
|
public JetType visitThrowExpression(JetThrowExpression expression, ExpressionTypingContext context) {
|
||||||
JetExpression thrownExpression = expression.getThrownExpression();
|
JetExpression thrownExpression = expression.getThrownExpression();
|
||||||
if (thrownExpression != null) {
|
if (thrownExpression != null) {
|
||||||
JetType type = facade.getType(thrownExpression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(context.scope));
|
JetType throwableType = context.semanticServices.getStandardLibrary().getThrowable().getDefaultType();
|
||||||
// TODO : check that it inherits Throwable
|
facade.getType(thrownExpression, context.replaceExpectedType(throwableType).replaceScope(context.scope));
|
||||||
}
|
}
|
||||||
return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context);
|
return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ public object SomeClass {
|
|||||||
|
|
||||||
public fun box():String {
|
public fun box():String {
|
||||||
if(SomeClass.bug is Throwable)
|
if(SomeClass.bug is Throwable)
|
||||||
throw SomeClass.bug
|
throw SomeClass.bug as Throwable
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ fun illegalReturnIf(): Char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun returnNothing(): Nothing {
|
fun returnNothing(): Nothing {
|
||||||
throw 1
|
throw <!ERROR_COMPILE_TIME_VALUE!>1<!>
|
||||||
}
|
}
|
||||||
fun f(): Int {
|
fun f(): Int {
|
||||||
if (1 < 2) { return 1 } else returnNothing()
|
if (1 < 2) { return 1 } else returnNothing()
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ fun t7() : Int {
|
|||||||
return 1
|
return 1
|
||||||
<!UNREACHABLE_CODE!>2<!>
|
<!UNREACHABLE_CODE!>2<!>
|
||||||
}
|
}
|
||||||
catch (e : Any) {
|
catch (<!TYPE_MISMATCH!>e : Any<!>) {
|
||||||
<!UNUSED_EXPRESSION!>2<!>
|
<!UNUSED_EXPRESSION!>2<!>
|
||||||
}
|
}
|
||||||
return 1 // this is OK, like in Java
|
return 1 // this is OK, like in Java
|
||||||
@@ -120,7 +120,7 @@ fun t8() : Int {
|
|||||||
return 1
|
return 1
|
||||||
<!UNREACHABLE_CODE!>2<!>
|
<!UNREACHABLE_CODE!>2<!>
|
||||||
}
|
}
|
||||||
catch (e : Any) {
|
catch (<!TYPE_MISMATCH!>e : Any<!>) {
|
||||||
return 1
|
return 1
|
||||||
<!UNREACHABLE_CODE!>2<!>
|
<!UNREACHABLE_CODE!>2<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ public class Throwables() {
|
|||||||
public fun propagateIfInstanceOf<X : Throwable?>(throwable : Throwable?, declaredType : Class<X?>?) {
|
public fun propagateIfInstanceOf<X : Throwable?>(throwable : Throwable?, declaredType : Class<X?>?) {
|
||||||
if (((throwable != null) && declaredType?.isInstance(throwable).sure()))
|
if (((throwable != null) && declaredType?.isInstance(throwable).sure()))
|
||||||
{
|
{
|
||||||
throw declaredType?.cast(throwable)
|
throw declaredType?.cast(throwable).sure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public fun propagateIfPossible(throwable : Throwable?) {
|
public fun propagateIfPossible(throwable : Throwable?) {
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ fun illegalReturnIf(): Char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun returnNothing(): Nothing {
|
fun returnNothing(): Nothing {
|
||||||
throw 1
|
throw <error>1</error>
|
||||||
}
|
}
|
||||||
fun f(): Int {
|
fun f(): Int {
|
||||||
if (1 < 2) { return 1 } else returnNothing()
|
if (1 < 2) { return 1 } else returnNothing()
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ fun t7() : Int {
|
|||||||
return 1
|
return 1
|
||||||
<error>2</error>
|
<error>2</error>
|
||||||
}
|
}
|
||||||
catch (e : Any) {
|
catch (<error>e : Any</error>) {
|
||||||
<warning>2</warning>
|
<warning>2</warning>
|
||||||
}
|
}
|
||||||
return 1 // this is OK, like in Java
|
return 1 // this is OK, like in Java
|
||||||
@@ -118,7 +118,7 @@ fun t8() : Int {
|
|||||||
return 1
|
return 1
|
||||||
<error>2</error>
|
<error>2</error>
|
||||||
}
|
}
|
||||||
catch (e : Any) {
|
catch (<error>e : Any</error>) {
|
||||||
return 1
|
return 1
|
||||||
<error>2</error>
|
<error>2</error>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ fun <T: Exception> failsWith(block: ()-> Any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun todo(block: ()-> Any) {
|
fun todo(block: ()-> Any) {
|
||||||
println("TODO at " + Exception().getStackTrace()?.get(1) + " for " + block)
|
println("TODO at " + (Exception() as java.lang.Throwable).getStackTrace()?.get(1) + " for " + block)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user