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
*/
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_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> myBreakTargets = new Stack<Label>();
@@ -574,10 +566,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
? ((JetEscapeStringTemplateEntry) entry).getUnescapedValue()
: entry.getText();
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));
}
}
@@ -972,7 +964,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.invokevirtual("jet/typeinfo/TypeInfo", "getClassObject", "()Ljava/lang/Object;");
v.checkcast(typeMapper.mapType(typeParameterDescriptor.getClassObjectType()));
return StackValue.onStack(OBJECT_TYPE);
return StackValue.onStack(JetTypeMapper.TYPE_OBJECT);
}
else {
// receiver
@@ -1693,7 +1685,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private StackValue generateNullSafeEquals(IElementType opToken, boolean leftNullable, boolean rightNullable) {
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) {
v.iconst(1);
v.xor(Type.INT_TYPE);
@@ -1706,7 +1698,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.ifnull(rightNull);
Label leftNull = new Label();
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) {
v.iconst(1);
v.xor(Type.INT_TYPE);
@@ -1731,7 +1723,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.pop();
Label leftNull = new Label();
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) {
v.iconst(1);
v.xor(Type.INT_TYPE);
@@ -1796,7 +1788,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private StackValue compareExpressionsOnStack(IElementType opToken, Type operandType) {
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);
operandType = Type.INT_TYPE;
}
@@ -1865,7 +1857,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.anew(type);
v.dup();
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) {
@@ -1885,7 +1877,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
public void invokeAppendMethod(Type exprType) {
Method appendDescriptor = new Method("append", JetTypeMapper.JL_STRING_BUILDER,
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
@@ -2331,7 +2323,7 @@ If finally block is present, its last expression is the value of try expression.
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
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();
v.ifne(isInstance);
v.pop();
@@ -2353,7 +2345,7 @@ If finally block is present, its last expression is the value of try expression.
@Override
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);
}
@@ -2376,7 +2368,7 @@ If finally block is present, its last expression is the value of try expression.
expressionToMatch.dupReceiver(v);
expressionToMatch.put(subjectType, v);
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);
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 lblDone = new Label();
expressionToMatch.dupReceiver(v);
expressionToMatch.put(OBJECT_TYPE, v);
expressionToMatch.put(JetTypeMapper.TYPE_OBJECT, v);
v.dup();
final String tupleClassName = "jet/Tuple" + entries.size();
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);
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);
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) {
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (!hasTypeInfoForInstanceOf(jetType)) {
expressionToGen.put(OBJECT_TYPE, v);
expressionToGen.put(JetTypeMapper.TYPE_OBJECT, v);
if (leaveExpressionOnStack) {
v.dup();
}
@@ -2491,7 +2483,7 @@ If finally block is present, its last expression is the value of try expression.
}
else {
generateTypeInfo(jetType);
expressionToGen.put(OBJECT_TYPE, v);
expressionToGen.put(JetTypeMapper.TYPE_OBJECT, v);
if (leaveExpressionOnStack) {
v.dupX1();
}
@@ -2718,7 +2710,7 @@ If finally block is present, its last expression is the value of try expression.
v.dup();
generateTypeInfo(new ProjectionErasingJetType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression)));
for (JetExpression entry : entries) {
gen(entry, OBJECT_TYPE);
gen(entry, JetTypeMapper.TYPE_OBJECT);
}
v.invokespecial(className, "<init>", signature.toString());
return StackValue.onStack(tupleType);
@@ -26,7 +26,7 @@ public class Concat implements IntrinsicMethod {
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"));
}
}
@@ -15,7 +15,6 @@ import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.plugin.JetFileType;
import org.objectweb.asm.Opcodes;
import sun.tools.tree.NewArrayExpression;
import java.util.*;
@@ -87,7 +86,7 @@ public class IntrinsicMethods {
declareOverload(myStdLib.getLibraryScope().getFunctions("identityEquals"), 1, EQUALS);
declareOverload(myStdLib.getLibraryScope().getFunctions("plus"), 1, new StringPlus());
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("ShortIterator", "next", 0, ITERATOR_NEXT);
@@ -13,11 +13,11 @@ import java.util.List;
/**
* @author alex.tkachman
*/
public class NPE implements IntrinsicMethod {
public class Sure implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
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);
return StackValue.onStack(expectedType);
}
+1 -1
View File
@@ -42,7 +42,7 @@ fun Any?.equals(other : Any?) : Boolean// = this === other
// Returns "null" for null
fun Any?.toString() : String// = this === other
fun <T : Any> T?.npe() : T
fun <T : Any> T?.sure() : T
fun String?.plus(other: Any?) : String
@@ -1,9 +1,9 @@
//KT-600 Problem with 'sure' extension function type inference
// +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() {
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;
import jet.runtime.Intrinsics;
import junit.framework.TestCase;
import org.jetbrains.jet.codegen.CodegenTestCase;
import java.lang.reflect.Method;
@@ -9,8 +8,8 @@ import java.lang.reflect.Method;
public class JetNpeTest extends CodegenTestCase {
public void testStackTrace () {
try {
Intrinsics.npe(null);
fail("No NPE thrown");
Intrinsics.sure(null);
fail("No Sure thrown");
}
catch (NullPointerException e) {
StackTraceElement stackTraceElement = e.getStackTrace()[0];
@@ -20,12 +19,13 @@ public class JetNpeTest extends CodegenTestCase {
}
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();
}
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");
assertThrows(box, NullPointerException.class, null);
}
+29 -1
View File
@@ -1,5 +1,7 @@
package jet.runtime;
import java.util.ArrayList;
/**
* @author alex.tkachman
*/
@@ -11,7 +13,7 @@ public class Intrinsics {
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)
return throwNpe();
return self;
@@ -20,4 +22,30 @@ public class Intrinsics {
private static Object throwNpe() {
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);
}
}