npe() renamed to sure()

This commit is contained in:
Alex Tkachman
2011-11-26 10:01:57 +02:00
parent 2cbd072478
commit 554aab83be
9 changed files with 58 additions and 71 deletions
@@ -35,18 +35,10 @@ import java.util.*;
* @author alex.tkachman * @author alex.tkachman
*/ */
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private static final String CLASS_OBJECT = "java/lang/Object";
private static final String CLASS_STRING = "java/lang/String";
public static final String CLASS_STRING_BUILDER = "java/lang/StringBuilder";
private static final String CLASS_COMPARABLE = "java/lang/Comparable";
private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException"; private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException";
private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException"; private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException";
private static final Type OBJECT_TYPE = Type.getType(Object.class);
private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
private static final Type STRING_TYPE = Type.getObjectType(CLASS_STRING);
private final Stack<Label> myContinueTargets = new Stack<Label>(); private final Stack<Label> myContinueTargets = new Stack<Label>();
private final Stack<Label> myBreakTargets = new Stack<Label>(); private final Stack<Label> myBreakTargets = new Stack<Label>();
@@ -574,10 +566,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
? ((JetEscapeStringTemplateEntry) entry).getUnescapedValue() ? ((JetEscapeStringTemplateEntry) entry).getUnescapedValue()
: entry.getText(); : entry.getText();
v.aconst(text); v.aconst(text);
invokeAppendMethod(STRING_TYPE); invokeAppendMethod(JetTypeMapper.JL_STRING_TYPE);
} }
} }
v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;"); v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
return StackValue.onStack(expressionType(expression)); return StackValue.onStack(expressionType(expression));
} }
} }
@@ -972,7 +964,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.invokevirtual("jet/typeinfo/TypeInfo", "getClassObject", "()Ljava/lang/Object;"); v.invokevirtual("jet/typeinfo/TypeInfo", "getClassObject", "()Ljava/lang/Object;");
v.checkcast(typeMapper.mapType(typeParameterDescriptor.getClassObjectType())); v.checkcast(typeMapper.mapType(typeParameterDescriptor.getClassObjectType()));
return StackValue.onStack(OBJECT_TYPE); return StackValue.onStack(JetTypeMapper.TYPE_OBJECT);
} }
else { else {
// receiver // receiver
@@ -1693,7 +1685,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private StackValue generateNullSafeEquals(IElementType opToken, boolean leftNullable, boolean rightNullable) { private StackValue generateNullSafeEquals(IElementType opToken, boolean leftNullable, boolean rightNullable) {
if(!leftNullable) { if(!leftNullable) {
v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z"); v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ) { if (opToken == JetTokens.EXCLEQ) {
v.iconst(1); v.iconst(1);
v.xor(Type.INT_TYPE); v.xor(Type.INT_TYPE);
@@ -1706,7 +1698,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.ifnull(rightNull); v.ifnull(rightNull);
Label leftNull = new Label(); Label leftNull = new Label();
v.ifnull(leftNull); v.ifnull(leftNull);
v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z"); v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
v.iconst(1); v.iconst(1);
v.xor(Type.INT_TYPE); v.xor(Type.INT_TYPE);
@@ -1731,7 +1723,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.pop(); v.pop();
Label leftNull = new Label(); Label leftNull = new Label();
v.ifnull(leftNull); v.ifnull(leftNull);
v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z"); v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
v.iconst(1); v.iconst(1);
v.xor(Type.INT_TYPE); v.xor(Type.INT_TYPE);
@@ -1796,7 +1788,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private StackValue compareExpressionsOnStack(IElementType opToken, Type operandType) { private StackValue compareExpressionsOnStack(IElementType opToken, Type operandType) {
if (operandType.getSort() == Type.OBJECT) { if (operandType.getSort() == Type.OBJECT) {
v.invokeinterface(CLASS_COMPARABLE, "compareTo", "(Ljava/lang/Object;)I"); v.invokeinterface("java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I");
v.iconst(0); v.iconst(0);
operandType = Type.INT_TYPE; operandType = Type.INT_TYPE;
} }
@@ -1865,7 +1857,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.anew(type); v.anew(type);
v.dup(); v.dup();
Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]); Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
v.invokespecial(CLASS_STRING_BUILDER, method.getName(), method.getDescriptor()); v.invokespecial("java/lang/StringBuilder", method.getName(), method.getDescriptor());
} }
public void invokeAppend(final JetExpression expr) { public void invokeAppend(final JetExpression expr) {
@@ -1885,7 +1877,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
public void invokeAppendMethod(Type exprType) { public void invokeAppendMethod(Type exprType) {
Method appendDescriptor = new Method("append", JetTypeMapper.JL_STRING_BUILDER, Method appendDescriptor = new Method("append", JetTypeMapper.JL_STRING_BUILDER,
new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType}); new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType});
v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor()); v.invokevirtual("java/lang/StringBuilder", "append", appendDescriptor.getDescriptor());
} }
@Override @Override
@@ -2331,7 +2323,7 @@ If finally block is present, its last expression is the value of try expression.
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) { if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
Type type = JetTypeMapper.boxType(typeMapper.mapType(jetType)); Type type = JetTypeMapper.boxType(typeMapper.mapType(jetType));
generateInstanceOf(StackValue.expression(OBJECT_TYPE, expression.getLeft(), this), jetType, true); generateInstanceOf(StackValue.expression(JetTypeMapper.TYPE_OBJECT, expression.getLeft(), this), jetType, true);
Label isInstance = new Label(); Label isInstance = new Label();
v.ifne(isInstance); v.ifne(isInstance);
v.pop(); v.pop();
@@ -2353,7 +2345,7 @@ If finally block is present, its last expression is the value of try expression.
@Override @Override
public StackValue visitIsExpression(final JetIsExpression expression, StackValue receiver) { public StackValue visitIsExpression(final JetIsExpression expression, StackValue receiver) {
final StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this); final StackValue match = StackValue.expression(JetTypeMapper.TYPE_OBJECT, expression.getLeftHandSide(), this);
return generatePatternMatch(expression.getPattern(), expression.isNegated(), match, null); return generatePatternMatch(expression.getPattern(), expression.isNegated(), match, null);
} }
@@ -2376,7 +2368,7 @@ If finally block is present, its last expression is the value of try expression.
expressionToMatch.dupReceiver(v); expressionToMatch.dupReceiver(v);
expressionToMatch.put(subjectType, v); expressionToMatch.put(subjectType, v);
JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression(); JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression();
Type condType = isNumberPrimitive(subjectType) ? expressionType(condExpression) : OBJECT_TYPE; Type condType = isNumberPrimitive(subjectType) ? expressionType(condExpression) : JetTypeMapper.TYPE_OBJECT;
gen(condExpression, condType); gen(condExpression, condType);
return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType, false, false); return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType, false, false);
} }
@@ -2407,7 +2399,7 @@ If finally block is present, its last expression is the value of try expression.
Label lblFail = new Label(); Label lblFail = new Label();
Label lblDone = new Label(); Label lblDone = new Label();
expressionToMatch.dupReceiver(v); expressionToMatch.dupReceiver(v);
expressionToMatch.put(OBJECT_TYPE, v); expressionToMatch.put(JetTypeMapper.TYPE_OBJECT, v);
v.dup(); v.dup();
final String tupleClassName = "jet/Tuple" + entries.size(); final String tupleClassName = "jet/Tuple" + entries.size();
Type tupleType = Type.getObjectType(tupleClassName); Type tupleType = Type.getObjectType(tupleClassName);
@@ -2421,7 +2413,7 @@ If finally block is present, its last expression is the value of try expression.
v.mark(lblCheck); v.mark(lblCheck);
for (int i = 0; i < entries.size(); i++) { for (int i = 0; i < entries.size(); i++) {
final StackValue tupleField = StackValue.field(OBJECT_TYPE, tupleClassName, "_" + (i + 1), false); final StackValue tupleField = StackValue.field(JetTypeMapper.TYPE_OBJECT, tupleClassName, "_" + (i + 1), false);
final StackValue stackValue = generatePatternMatch(entries.get(i).getPattern(), false, tupleField, nextEntry); final StackValue stackValue = generatePatternMatch(entries.get(i).getPattern(), false, tupleField, nextEntry);
stackValue.condJump(lblPopAndFail, true, v); stackValue.condJump(lblPopAndFail, true, v);
} }
@@ -2467,7 +2459,7 @@ If finally block is present, its last expression is the value of try expression.
private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) { private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) {
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (!hasTypeInfoForInstanceOf(jetType)) { if (!hasTypeInfoForInstanceOf(jetType)) {
expressionToGen.put(OBJECT_TYPE, v); expressionToGen.put(JetTypeMapper.TYPE_OBJECT, v);
if (leaveExpressionOnStack) { if (leaveExpressionOnStack) {
v.dup(); v.dup();
} }
@@ -2491,7 +2483,7 @@ If finally block is present, its last expression is the value of try expression.
} }
else { else {
generateTypeInfo(jetType); generateTypeInfo(jetType);
expressionToGen.put(OBJECT_TYPE, v); expressionToGen.put(JetTypeMapper.TYPE_OBJECT, v);
if (leaveExpressionOnStack) { if (leaveExpressionOnStack) {
v.dupX1(); v.dupX1();
} }
@@ -2718,7 +2710,7 @@ If finally block is present, its last expression is the value of try expression.
v.dup(); v.dup();
generateTypeInfo(new ProjectionErasingJetType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression))); generateTypeInfo(new ProjectionErasingJetType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression)));
for (JetExpression entry : entries) { for (JetExpression entry : entries) {
gen(entry, OBJECT_TYPE); gen(entry, JetTypeMapper.TYPE_OBJECT);
} }
v.invokespecial(className, "<init>", signature.toString()); v.invokespecial(className, "<init>", signature.toString());
return StackValue.onStack(tupleType); return StackValue.onStack(tupleType);
@@ -26,7 +26,7 @@ public class Concat implements IntrinsicMethod {
codegen.invokeAppend(arguments.get(1)); codegen.invokeAppend(arguments.get(1));
} }
v.invokevirtual(ExpressionCodegen.CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;"); v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
return StackValue.onStack(Type.getObjectType("java/lang/String")); return StackValue.onStack(Type.getObjectType("java/lang/String"));
} }
} }
@@ -15,7 +15,6 @@ import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.plugin.JetFileType; import org.jetbrains.jet.plugin.JetFileType;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import sun.tools.tree.NewArrayExpression;
import java.util.*; import java.util.*;
@@ -87,7 +86,7 @@ public class IntrinsicMethods {
declareOverload(myStdLib.getLibraryScope().getFunctions("identityEquals"), 1, EQUALS); declareOverload(myStdLib.getLibraryScope().getFunctions("identityEquals"), 1, EQUALS);
declareOverload(myStdLib.getLibraryScope().getFunctions("plus"), 1, new StringPlus()); declareOverload(myStdLib.getLibraryScope().getFunctions("plus"), 1, new StringPlus());
declareOverload(myStdLib.getLibraryScope().getFunctions("Array"), 1, new NewArray()); declareOverload(myStdLib.getLibraryScope().getFunctions("Array"), 1, new NewArray());
declareOverload(myStdLib.getLibraryScope().getFunctions("npe"), 0, new NPE()); declareOverload(myStdLib.getLibraryScope().getFunctions("sure"), 0, new Sure());
declareIntrinsicFunction("ByteIterator", "next", 0, ITERATOR_NEXT); declareIntrinsicFunction("ByteIterator", "next", 0, ITERATOR_NEXT);
declareIntrinsicFunction("ShortIterator", "next", 0, ITERATOR_NEXT); declareIntrinsicFunction("ShortIterator", "next", 0, ITERATOR_NEXT);
@@ -13,11 +13,11 @@ import java.util.List;
/** /**
* @author alex.tkachman * @author alex.tkachman
*/ */
public class NPE implements IntrinsicMethod { public class Sure implements IntrinsicMethod {
@Override @Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) { public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
receiver.put(JetTypeMapper.TYPE_OBJECT, v); receiver.put(JetTypeMapper.TYPE_OBJECT, v);
v.invokestatic("jet/runtime/Intrinsics", "npe", "(Ljava/lang/Object;)Ljava/lang/Object;"); v.invokestatic("jet/runtime/Intrinsics", "sure", "(Ljava/lang/Object;)Ljava/lang/Object;");
StackValue.onStack(JetTypeMapper.TYPE_OBJECT).put(expectedType, v); StackValue.onStack(JetTypeMapper.TYPE_OBJECT).put(expectedType, v);
return StackValue.onStack(expectedType); return StackValue.onStack(expectedType);
} }
+1 -1
View File
@@ -42,7 +42,7 @@ fun Any?.equals(other : Any?) : Boolean// = this === other
// Returns "null" for null // Returns "null" for null
fun Any?.toString() : String// = this === other fun Any?.toString() : String// = this === other
fun <T : Any> T?.npe() : T fun <T : Any> T?.sure() : T
fun String?.plus(other: Any?) : String fun String?.plus(other: Any?) : String
@@ -1,9 +1,9 @@
//KT-600 Problem with 'sure' extension function type inference //KT-600 Problem with 'sure' extension function type inference
// +JDK // +JDK
fun <T : Any> T?.sure() : T { if (this != null) return this else throw NullPointerException() } fun <T : Any> T?._sure() : T { if (this != null) return this else throw NullPointerException() }
fun test() { fun test() {
val i : Int? = 10 val i : Int? = 10
val <!UNUSED_VARIABLE!>i2<!> : Int = i.sure() // inferred type is Int? but Int was excepted val <!UNUSED_VARIABLE!>i2<!> : Int = i._sure() // inferred type is Int? but Int was excepted
} }
@@ -1,7 +1,6 @@
package org.jetbrains.jet.runtime; package org.jetbrains.jet.runtime;
import jet.runtime.Intrinsics; import jet.runtime.Intrinsics;
import junit.framework.TestCase;
import org.jetbrains.jet.codegen.CodegenTestCase; import org.jetbrains.jet.codegen.CodegenTestCase;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -9,8 +8,8 @@ import java.lang.reflect.Method;
public class JetNpeTest extends CodegenTestCase { public class JetNpeTest extends CodegenTestCase {
public void testStackTrace () { public void testStackTrace () {
try { try {
Intrinsics.npe(null); Intrinsics.sure(null);
fail("No NPE thrown"); fail("No Sure thrown");
} }
catch (NullPointerException e) { catch (NullPointerException e) {
StackTraceElement stackTraceElement = e.getStackTrace()[0]; StackTraceElement stackTraceElement = e.getStackTrace()[0];
@@ -20,12 +19,13 @@ public class JetNpeTest extends CodegenTestCase {
} }
public void testNotNull () throws Exception { public void testNotNull () throws Exception {
loadText("fun box() = if(10.npe() == 10) \"OK\" else \"fail\""); loadText("fun box() = if(10.sure() == 10) \"OK\" else \"fail\"");
blackBox(); blackBox();
} }
public void testNull () throws Exception { public void testNull () throws Exception {
loadText("fun box() = if(null.npe() == 10) \"OK\" else \"fail\""); loadText("fun box() = if(null.sure() == 10) \"OK\" else \"fail\"");
System.out.println(generateToText());
Method box = generateFunction("box"); Method box = generateFunction("box");
assertThrows(box, NullPointerException.class, null); assertThrows(box, NullPointerException.class, null);
} }
+29 -1
View File
@@ -1,5 +1,7 @@
package jet.runtime; package jet.runtime;
import java.util.ArrayList;
/** /**
* @author alex.tkachman * @author alex.tkachman
*/ */
@@ -11,7 +13,7 @@ public class Intrinsics {
return ((self == null) ? "null" : self) + ((other == null) ? "null" : other.toString()); return ((self == null) ? "null" : self) + ((other == null) ? "null" : other.toString());
} }
public static Object npe(Object self) { public static Object sure(Object self) {
if(self == null) if(self == null)
return throwNpe(); return throwNpe();
return self; return self;
@@ -20,4 +22,30 @@ public class Intrinsics {
private static Object throwNpe() { private static Object throwNpe() {
throw new JetNullPointerException(); throw new JetNullPointerException();
} }
private static Throwable sanitizeStackTrace(Throwable throwable) {
StackTraceElement[] stackTrace = throwable.getStackTrace();
ArrayList<StackTraceElement> list = new ArrayList<StackTraceElement>();
boolean skip = true;
for(StackTraceElement ste : stackTrace) {
if(!skip) {
list.add(ste);
}
else {
if("jet.runtime.Intrinsics".equals(ste.getClassName()) && "sure".equals(ste.getMethodName())) {
skip = false;
}
}
}
throwable.setStackTrace(list.toArray(new StackTraceElement[list.size()]));
return throwable;
}
private static class JetNullPointerException extends NullPointerException {
@Override
public synchronized Throwable fillInStackTrace() {
super.fillInStackTrace();
return sanitizeStackTrace(this);
}
}
} }
@@ -1,32 +0,0 @@
package jet.runtime;
import java.util.ArrayList;
/**
* @author alex.tkachman
*/
class JetNullPointerException extends NullPointerException {
@Override
public synchronized Throwable fillInStackTrace() {
super.fillInStackTrace();
StackTraceElement[] stackTrace = getStackTrace();
ArrayList<StackTraceElement> list = new ArrayList<StackTraceElement>();
boolean skip = true;
for(StackTraceElement ste : stackTrace) {
if(!skip) {
list.add(ste);
}
else {
if("jet.runtime.Intrinsics".equals(ste.getClassName()) && "npe".equals(ste.getMethodName())) {
skip = false;
}
}
}
setStackTrace(list.toArray(new StackTraceElement[list.size()]));
return this;
}
public static void main(String[] args) {
Intrinsics.npe(null);
}
}