KT-1041 Add check that thrown/catched expression is of Throwable type

This commit is contained in:
Svetlana Isakova
2012-02-20 13:46:34 +04:00
parent 3d3b41da4f
commit 046c13a264
12 changed files with 47 additions and 13 deletions
@@ -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();
@@ -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;
} }
+6
View File
@@ -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) {
@@ -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()
+2 -2
View File
@@ -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>
} }
+1 -1
View File
@@ -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)
} }
/* /*