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