Freitag, 10. Januar 14

Werbung
Organisatorisches
Freitag, 10. Januar 14
Klausur - Spickzettel
• Es gibt ein Google Docs File
• https://docs.google.com/document/d/1-
eBQcOpKYQKDsduN95Ui7CgVC0kAQTj
Yq0Hpw6PsC4s/edit
• Editiert es nach Belieben
• In der letzten Übung stellen wir den
Spickzettel zusammen
Freitag, 10. Januar 14
Wiederholung
• Es wird noch ein Übungsblatt geben
• Besprechung ist am 23.1
• Am 30.1 mache ich in der Übung eine
Wiederholung
• Am 6.2 besprechen wir den Spickzettel und
machen nochmal eine Fragestunde
• Beginn der Übung am 30.1 und 6.2 um 8:30
Uhr
Freitag, 10. Januar 14
Projekt
Die Clojure
Bibliothek ist
euer Freund!
Freitag, 10. Januar 14
Macros
Freitag, 10. Januar 14
Wiederholung
•
Evaluationsstrategien
Funktionen (Argumente rekursiv evaluieren)
Macros (Argumente unevaluiert als Form)
Special Forms (Spezialregeln - idR wie Macros)
Quoting
'
` ~ ~@ #
Macros sollen sparsam eingesetzt werden
Für AOT-Berechnung
Für Syntax-Zucker
Macros sind Hooks in den Compiler / kleine Compiler
•
•
•
•
•
•
•
•
•
•
Freitag, 10. Januar 14
Warum Macros?
Freitag, 10. Januar 14
Once upon a time
•
•
Freitag, 10. Januar 14
Project Coin
Teil von Java 7, kleine Sprachänderungen
Switch mit Strings
Literale für Binärzahlen
Underscores in Zahl-Literalen
Multicatch
Diamond Operator
Try with resource
•
•
•
•
•
•
Try with Resource
public class OldTry {
public static void main(String[] args) {
OldResource res = null;
try {
res = new OldResource();
res.doSomeWork("Writing an article");
} catch (Exception e) {
System.out.println(e.getMessage());
} finally{
try {
res.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
Freitag, 10. Januar 14
Try with Resource
public class TryWithRes {
public static void main(String[] args) {
try(NewResource res = new NewResource("close msg")){
res.doSomeWork("Listening to podcast");
} catch(Exception e){
System.out.println(e.getMessage());
}
}
}
Freitag, 10. Januar 14
So you want to change the Java Programming Language...
By darcy on May 28, 2007
With the talk of closures, modules, more annotations, and other language features in
the air for JDK 7, what are all the tasks that might need to happen to fully add a
language feature to the platform? Besides the general advice of being open about the
project's status and soliciting feedback, there are specific technical considerations for
language changes. Designing language features generates a lot of interest so providing
a design rationale and FAQ is especially important. Based on my experiences helping
out with adding the host of language features in JDK 5, there are many interactions to
consider; while some of them are obvious, others are quite surprising. The following list
is not exhaustive, but everything on the list is an item to consider:
Freitag, 10. Januar 14
Update the Java Language Specification. This is obviously a required task for a language change, but the JLS is
a large and complicated document and it may not be immediately obvious how and where all the updates need to
occur. Considering the JLS roughly chapter by chapter:
◦
How does the grammar need to be revised?
◦
How is the type system affected?
◦
Are any new conversions defined?
◦
Are naming conventions or name visibility modified?
◦
Is the existing structure of packages, classes, or interfaces changed?
◦
How can the new feature be annotated?
◦
Is method resolution impacted?
◦
How does the change impact source compatibility?
◦
How does the change impact binary compatibility?
◦
Does the feature affect the reachability of code or the definite assignment of variables?
◦
Compute the Buckley Complexity Quotient of your change.
Implement the language change in a compiler. Sun's javac compiler has been open-sourced and experiments
are welcome in the Kitchen Sink Language project. Be warned, the kitchen sink may have a garbage disposal.
However, batch compiler support alone is not sufficient; language changes today should have IDE support too.
Add any essential library support. Some language changes rely on concomitant library updates. For example, all
enum types are subclasses of java.lang.Enum.
Freitag, 10. Januar 14
+
+
--- a/make/build.properties!
Thu Jul 15 16:31:56 2010 +0100
+++ b/make/build.properties!
Fri Jul 16 19:35:24 2010 -0700
@@ -107,7 +107,8 @@ javac.includes = \
javax/annotation/processing/ \
javax/lang/model/ \
javax/tools/ \
com/sun/source/ com/sun/tools/javac/
+
com/sun/source/ \
+
com/sun/tools/javac/
/** Derived visitor method: attribute an expression tree with
@@ -976,14 +995,34 @@ public class Attr extends JCTree.Visitor
}
javac.tests = \
tools/javac
--- a/src/share/classes/com/sun/source/tree/TryTree.java!
Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/source/tree/TryTree.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -49,4 +49,5 @@ public interface TryTree extends Stateme
BlockTree getBlock();
List<? extends CatchTree> getCatches();
BlockTree getFinallyBlock();
+
List<? extends Tree> getResources();
}
--- a/src/share/classes/com/sun/source/util/TreeScanner.java!
Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/source/util/TreeScanner.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -209,7 +209,8 @@ public class TreeScanner<R,P> implements
}
public R visitTry(TryTree node, P p) {
R r = scan(node.getBlock(), p);
R r = scan(node.getResources(), p);
r = scanAndReduce(node.getBlock(), p, r);
r = scanAndReduce(node.getCatches(), p, r);
r = scanAndReduce(node.getFinallyBlock(), p, r);
return r;
--- a/src/share/classes/com/sun/tools/javac/code/Lint.java! Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Lint.java! Fri Jul 16 19:35:24 2010 -0700
@@ -208,7 +208,12 @@ public class Lint
/**
* Warn about potentially unsafe vararg methods
*/
VARARGS("varargs");
+
VARARGS("varargs"),
+
+
/**
+
* Warn about arm resources
+
*/
+
ARM("arm");
+
+
LintCategory(String option) {
this(option, false);
--- a/src/share/classes/com/sun/tools/javac/code/Source.java!
+++ b/src/share/classes/com/sun/tools/javac/code/Source.java!
@@ -159,6 +159,9 @@ public enum Source {
public boolean enforceMandatoryWarnings() {
return compareTo(JDK1_5) >= 0;
}
+
public boolean allowTryWithResources() {
+
return compareTo(JDK1_7) >= 0;
+
}
public boolean allowTypeAnnotations() {
return compareTo(JDK1_7) >= 0;
}
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java!
+++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java!
@@ -993,12 +993,17 @@ public abstract class Symbol implements
return data == ElementKind.EXCEPTION_PARAMETER;
}
+
+
+
+
Thu Jul 15 16:31:56 2010 +0100
Fri Jul 16 19:35:24 2010 -0700
public boolean isResourceVariable() {
return data == ElementKind.RESOURCE_VARIABLE;
}
public
//
if
if
/** The symbol representing the final finalize method on enums */
public final MethodSymbol enumFinalFinalize;
/** The symbol representing the close method on TWR AutoCloseable type */
public final MethodSymbol autoCloseableClose;
/** The predefined type that belongs to a tag.
*/
@@ -444,6 +448,12 @@ public class Symtab {
suppressWarningsType = enterClass("java.lang.SuppressWarnings");
inheritedType = enterClass("java.lang.annotation.Inherited");
systemType = enterClass("java.lang.System");
+
autoCloseableType = enterClass("java.lang.AutoCloseable");
+
autoCloseableClose = new MethodSymbol(PUBLIC,
+
names.close,
+
new MethodType(List.<Type>nil(), voidType,
+
List.of(exceptionType), methodClass),
+
autoCloseableType.tsym);
synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType);
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java! Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java! Fri Jul 16 19:35:24 2010 -0700
@@ -192,7 +192,7 @@ public class Attr extends JCTree.Visitor
Type check(JCTree tree, Type owntype, int ownkind, int pkind, Type pt) {
if (owntype.tag != ERROR && pt.tag != METHOD && pt.tag != FORALL) {
if ((ownkind & ~pkind) == 0) {
owntype = chk.checkType(tree.pos(), owntype, pt);
+
owntype = chk.checkType(tree.pos(), owntype, pt, errKey);
} else {
log.error(tree.pos(), "unexpected.type",
kindNames(pkind),
@@ -239,7 +239,11 @@ public class Attr extends JCTree.Visitor
!((base == null ||
(base.getTag() == JCTree.IDENT && TreeInfo.name(base) == names._this)) &&
isAssignableAsBlankFinal(v, env)))) {
log.error(pos, "cant.assign.val.to.final.var", v);
+
if (v.isResourceVariable()) { //TWR resource
+
log.error(pos, "twr.resource.may.not.be.assigned", v);
+
} else {
+
log.error(pos, "cant.assign.val.to.final.var", v);
+
}
}
}
@@ -372,6 +376,10 @@ public class Attr extends JCTree.Visitor
*/
Type pt;
+
+
+
+
/** Visitor argument: the error key to be generated when a type error occurs
*/
String errKey;
/** Visitor result: the computed type.
*/
Type result;
@@ -385,13 +393,19 @@ public class Attr extends JCTree.Visitor
* @param pt
The prototype visitor argument.
*/
Type attribTree(JCTree tree, Env<AttrContext> env, int pkind, Type pt) {
+
return attribTree(tree, env, pkind, pt, "incompatible.types");
+
}
+
+
Type attribTree(JCTree tree, Env<AttrContext> env, int pkind, Type pt, String errKey) {
Env<AttrContext> prevEnv = this.env;
int prevPkind = this.pkind;
Type prevPt = this.pt;
+
String prevErrKey = this.errKey;
try {
this.env = env;
this.pkind = pkind;
this.pt = pt;
+
this.errKey = errKey;
tree.accept(this);
if (tree == breakTree)
throw new BreakAttr(env);
@@ -403,6 +417,7 @@ public class Attr extends JCTree.Visitor
this.env = prevEnv;
this.pkind = prevPkind;
this.pt = prevPt;
+
this.errKey = prevErrKey;
}
}
@@ -410,6 +425,10 @@ public class Attr extends JCTree.Visitor
*/
public Type attribExpr(JCTree tree, Env<AttrContext> env, Type pt) {
return attribTree(tree, env, VAL, pt.tag != ERROR ? pt : Type.noType);
+
}
+
Freitag, 10. Januar 14
+
+
+
public void visitTry(JCTry tree) {
// Create a new local environment with a local
Env<AttrContext> localEnv = env.dup(tree, env.info.dup(env.info.scope.dup()));
boolean isTryWithResource = tree.resources.nonEmpty();
// Create a nested environment for attributing the try block if needed
Env<AttrContext> tryEnv = isTryWithResource ?
env.dup(tree, localEnv.info.dup(localEnv.info.scope.dup())) :
localEnv;
// Attribute resource declarations
for (JCTree resource : tree.resources) {
if (resource.getTag() == JCTree.VARDEF) {
attribStat(resource, tryEnv);
chk.checkType(resource, resource.type, syms.autoCloseableType, "twr.not.applicable.to.type");
VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
var.setData(ElementKind.RESOURCE_VARIABLE);
} else {
attribExpr(resource, tryEnv, syms.autoCloseableType, "twr.not.applicable.to.type");
}
}
// Attribute body
attribStat(tree.body, env.dup(tree, env.info.dup()));
attribStat(tree.body, tryEnv);
if (isTryWithResource)
tryEnv.info.scope.leave();
// Attribute catch clauses
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
JCCatch c = l.head;
Env<AttrContext> catchEnv =
env.dup(c, env.info.dup(env.info.scope.dup()));
+
localEnv.dup(c, localEnv.info.dup(localEnv.info.scope.dup()));
Type ctype = attribStat(c.param, catchEnv);
if (TreeInfo.isMultiCatch(c)) {
//check that multi-catch parameter is marked as final
@@ -1003,7 +1042,9 @@ public class Attr extends JCTree.Visitor
}
// Attribute finalizer
if (tree.finalizer != null) attribStat(tree.finalizer, env);
if (tree.finalizer != null) attribStat(tree.finalizer, localEnv);
+
+
+
localEnv.info.scope.leave();
result = null;
}
@@ -2139,6 +2180,15 @@ public class Attr extends JCTree.Visitor
checkAssignable(tree.pos(), v, tree.selected, env);
}
/** The symbol representing the length field of an array.
*/
@@ -158,6 +159,9 @@ public class Symtab {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Thu Jul 15 16:31:56 2010 +0100
Fri Jul 16 19:35:24 2010 -0700
Object getConstValue() {
TODO: Consider if getConstValue and getConstantValue can be collapsed
(data == ElementKind.EXCEPTION_PARAMETER) {
(data == ElementKind.EXCEPTION_PARAMETER ||
data == ElementKind.RESOURCE_VARIABLE) {
return null;
} else if (data instanceof Callable<?>) {
// In this case, this is final a variable, with an as
+
// In this case, this is a final variable, with an as
// yet unevaluated initializer.
Callable<?> eval = (Callable<?>)data;
data = null; // to make sure we don't evaluate this twice.
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java!
Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -148,6 +148,7 @@ public class Symtab {
public final Type inheritedType;
public final Type proprietaryType;
public final Type systemType;
+
public final Type autoCloseableType;
+
+
public Type attribExpr(JCTree tree, Env<AttrContext> env, Type pt, String key) {
return attribTree(tree, env, VAL, pt.tag != ERROR ? pt : Type.noType, key);
}
+
+
+
+
+
+
+
+
+
if (sitesym != null &&
sitesym.kind == VAR &&
((VarSymbol)sitesym).isResourceVariable() &&
sym.kind == MTH &&
sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true) &&
env.info.lint.isEnabled(Lint.LintCategory.ARM)) {
log.warning(tree, "twr.explicit.close.call");
}
// Disallow selecting a type from an expression
if (isType(sym) && (sitesym==null || (sitesym.kind&(TYP|PCK)) == 0)) {
tree.type = check(tree.selected, pt,
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java! Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java! Fri Jul 16 19:35:24 2010 -0700
@@ -393,6 +393,10 @@ public class Check {
* @param req
The type that was required.
*/
Type checkType(DiagnosticPosition pos, Type found, Type req) {
+
return checkType(pos, found, req, "incompatible.types");
+
}
+
+
Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) {
if (req.tag == ERROR)
return req;
if (found.tag == FORALL)
@@ -411,7 +415,7 @@ public class Check {
log.error(pos, "assignment.to.extends-bound", req);
return types.createErrorType(found);
}
return typeError(pos, diags.fragment("incompatible.types"), found, req);
+
return typeError(pos, diags.fragment(errKey), found, req);
}
/** Instantiate polymorphic type to some prototype, unless
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java! Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java! Fri Jul 16 19:35:24 2010 -0700
@@ -28,6 +28,8 @@ package com.sun.tools.javac.comp;
package com.sun.tools.javac.comp;
import java.util.HashMap;
+import java.util.Map;
+import java.util.LinkedHashMap;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.tree.*;
@@ -265,6 +267,10 @@ public class Flow extends TreeScanner {
*/
List<Type> caught;
+
+
+
+
/** The list of unreferenced automatic resources.
*/
Map<VarSymbol, JCVariableDecl> unrefdResources;
/** Set when processing a loop body the second time for DU analysis. */
boolean loopPassTwo = false;
@@ -963,6 +969,7 @@ public class Flow extends TreeScanner {
public void visitTry(JCTry tree) {
List<Type> caughtPrev = caught;
List<Type> thrownPrev = thrown;
+
Map<VarSymbol, JCVariableDecl> unrefdResourcesPrev = unrefdResources;
thrown = List.nil();
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
@@ -977,6 +984,32 @@ public class Flow extends TreeScanner {
pendingExits = new ListBuffer<PendingExit>();
Bits initsTry = inits.dup();
uninitsTry = uninits.dup();
+
unrefdResources = new LinkedHashMap<VarSymbol, JCVariableDecl>();
+
for (JCTree resource : tree.resources) {
+
if (resource instanceof JCVariableDecl) {
+
JCVariableDecl vdecl = (JCVariableDecl) resource;
+
visitVarDef(vdecl);
+
unrefdResources.put(vdecl.sym, vdecl);
+
} else if (resource instanceof JCExpression) {
+
scanExpr((JCExpression) resource);
+
} else {
+
throw new AssertionError(tree); // parser error
+
}
+
}
+
for (JCTree resource : tree.resources) {
+
MethodSymbol topCloseMethod = (MethodSymbol)syms.autoCloseableType.tsym.members().lookup(names.close).sym;
+
List<Type> closeableSupertypes = resource.type.isCompound() ?
+
types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
+
List.of(resource.type);
+
for (Type sup : closeableSupertypes) {
+
if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
+
MethodSymbol closeMethod = types.implementation(topCloseMethod, sup.tsym, types, true);
+
for (Type t : closeMethod.getThrownTypes()) {
+
markThrown(tree.body, t);
+
}
+
}
+
}
+
}
scanStat(tree.body);
List<Type> thrownInTry = thrown;
thrown = thrownPrev;
@@ -986,6 +1019,14 @@ public class Flow extends TreeScanner {
Bits initsEnd = inits;
Bits uninitsEnd = uninits;
int nextadrCatch = nextadr;
+
+
if (!unrefdResources.isEmpty() &&
+
lint.isEnabled(Lint.LintCategory.ARM)) {
+
for (Map.Entry<VarSymbol, JCVariableDecl> e : unrefdResources.entrySet()) {
+
log.warning(e.getValue().pos(),
+
"automatic.resource.not.referenced", e.getKey());
+
}
+
}
List<Type> caughtInTry = List.nil();
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
@@ -1070,6 +1111,7 @@ public class Flow extends TreeScanner {
while (exits.nonEmpty()) pendingExits.append(exits.next());
}
uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
+
unrefdResources = unrefdResourcesPrev;
}
public void visitConditional(JCConditional tree) {
@@ -1293,8 +1335,16 @@ public class Flow extends TreeScanner {
}
+
+
+
+
+
+
public void visitIdent(JCIdent tree) {
if (tree.sym.kind == VAR)
if (tree.sym.kind == VAR) {
checkInit(tree.pos(), (VarSymbol)tree.sym);
referenced(tree.sym);
}
}
void referenced(Symbol sym) {
+
+
+
if (unrefdResources != null && unrefdResources.containsKey(sym)) {
unrefdResources.remove(sym);
}
}
public void visitTypeCast(JCTypeCast tree) {
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java! Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java! Fri Jul 16 19:35:24 2010 -0700
@@ -603,6 +603,23 @@ public class Lower extends TreeTranslato
*/
private void enterSynthetic(DiagnosticPosition pos, Symbol sym, Scope s) {
s.enter(sym);
+
}
+
+
/** Create a fresh synthetic name within a given scope - the unique name is
+
* obtained by appending '$' chars at the end of the name until no match
+
* is found.
+
*
+
* @param name base name
+
* @param s scope in which the name has to be unique
+
* @return fresh synthetic name
+
*/
+
private Name makeSyntheticName(Name name, Scope s) {
+
do {
+
name = name.append(
+
target.syntheticNameChar(),
+
names.empty);
+
} while (lookupSynthetic(name, s) != null);
+
return name;
}
/** Check whether synthetic symbols generated during lowering conflict
@@ -1299,6 +1316,11 @@ public class Lower extends TreeTranslato
*/
Scope proxies;
+
+
+
+
+
/** A scope containing all unnamed resource variables/saved
* exception variables for translated TWR blocks
*/
Scope twrVars;
/** A stack containing the this$n field of the currently translated
* classes (if needed) in innermost first order.
* Inside a constructor, proxies and any this$n symbol are duplicated
@@ -1398,6 +1420,122 @@ public class Lower extends TreeTranslato
// need to go via this$n
return makeOuterThis(pos, c);
}
+
}
+
+
/** Optionally replace a try statement with an automatic resource
+
* management (ARM) block.
+
* @param tree The try statement to inspect.
+
* @return
An ARM block, or the original try block if there are no
+
*
resources to manage.
+
*/
+
JCTree makeArmTry(JCTry tree) {
+
make_at(tree.pos());
+
twrVars = twrVars.dup();
+
JCBlock armBlock = makeArmBlock(tree.resources, tree.body, 0);
+
if (tree.catchers.isEmpty() && tree.finalizer == null)
+
result = translate(armBlock);
+
else
+
result = translate(make.Try(armBlock, tree.catchers, tree.finalizer));
+
twrVars = twrVars.leave();
+
return result;
+
}
+
+
private JCBlock makeArmBlock(List<JCTree> resources, JCBlock block, int depth) {
+
if (resources.isEmpty())
+
return block;
+
+
// Add resource declaration or expression to block statements
+
ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
+
JCTree resource = resources.head;
+
JCExpression expr = null;
+
if (resource instanceof JCVariableDecl) {
+
JCVariableDecl var = (JCVariableDecl) resource;
+
expr = make.Ident(var.sym).setType(resource.type);
+
stats.add(var);
+
} else {
+
assert resource instanceof JCExpression;
+
VarSymbol syntheticTwrVar =
+
new VarSymbol(SYNTHETIC | FINAL,
+
makeSyntheticName(names.fromString("twrVar" +
+
depth), twrVars),
+
(resource.type.tag == TypeTags.BOT) ?
+
syms.autoCloseableType : resource.type,
+
currentMethodSym);
+
twrVars.enter(syntheticTwrVar);
+
JCVariableDecl syntheticTwrVarDecl =
+
make.VarDef(syntheticTwrVar, (JCExpression)resource);
+
expr = (JCExpression)make.Ident(syntheticTwrVar);
+
stats.add(syntheticTwrVarDecl);
+
}
+
+
// Add primaryException declaration
+
VarSymbol primaryException =
+
new VarSymbol(SYNTHETIC,
+
makeSyntheticName(names.fromString("primaryException" +
+
depth), twrVars),
+
syms.throwableType,
+
currentMethodSym);
+
twrVars.enter(primaryException);
+
JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull());
+
stats.add(primaryExceptionTreeDecl);
+
+
// Create catch clause that saves exception and then rethrows it
+
VarSymbol param =
+
new VarSymbol(FINAL|SYNTHETIC,
+
names.fromString("t" +
+
target.syntheticNameChar()),
+
syms.throwableType,
+
currentMethodSym);
+
JCVariableDecl paramTree = make.VarDef(param, null);
+
JCStatement assign = make.Assignment(primaryException, make.Ident(param));
+
JCStatement rethrowStat = make.Throw(make.Ident(param));
+
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat));
+
JCCatch catchClause = make.Catch(paramTree, catchBlock);
+
+
int oldPos = make.pos;
+
make.at(TreeInfo.endPos(block));
+
JCBlock finallyClause = makeArmFinallyClause(primaryException, expr);
+
make.at(oldPos);
+
JCTry outerTry = make.Try(makeArmBlock(resources.tail, block, depth + 1),
+
List.<JCCatch>of(catchClause),
+
finallyClause);
+
stats.add(outerTry);
+
return make.Block(0L, stats.toList());
+
}
+
+
private JCBlock makeArmFinallyClause(Symbol primaryException, JCExpression resource) {
+
// primaryException.addSuppressedException(catchException);
+
VarSymbol catchException =
+
new VarSymbol(0, make.paramName(2),
+
syms.throwableType,
+
currentMethodSym);
+
JCStatement addSuppressionStatement =
+
make.Exec(makeCall(make.Ident(primaryException),
+
names.fromString("addSuppressedException"),
+
List.<JCExpression>of(make.Ident(catchException))));
+
+
// try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); }
+
JCBlock tryBlock =
+
make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource)));
+
JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null);
+
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
+
List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
+
JCTry tryTree = make.Try(tryBlock, catchClauses, null);
+
+
// if (resource != null) resourceClose;
+
JCExpression nullCheck = makeBinary(JCTree.NE,
+
make.Ident(primaryException),
+
makeNull());
+
JCIf closeIfStatement = make.If(nullCheck,
+
tryTree,
+
makeResourceCloseInvocation(resource));
+
return make.Block(0L, List.<JCStatement>of(closeIfStatement));
+
}
+
+
private JCStatement makeResourceCloseInvocation(JCExpression resource) {
+
// create resource.close() method invocation
+
JCExpression resourceClose = makeCall(resource, names.close, List.<JCExpression>nil());
+
return make.Exec(resourceClose);
}
/** Construct a tree that represents the outer instance
@@ -3405,6 +3543,15 @@ public class Lower extends TreeTranslato
result = tree;
}
+
+
+
+
+
+
+
+
+
@Override
public void visitTry(JCTry tree) {
if (tree.resources.isEmpty()) {
super.visitTry(tree);
} else {
result = makeArmTry(tree);
}
}
/**************************************************************************
* main method
*************************************************************************/
@@ -3430,6 +3577,7 @@ public class Lower extends TreeTranslato
actualSymbols = new HashMap<Symbol,Symbol>();
freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>();
proxies = new Scope(syms.noSymbol);
+
twrVars = new Scope(syms.noSymbol);
outerThisStack = List.nil();
accessNums = new HashMap<Symbol,Integer>();
accessSyms = new HashMap<Symbol,MethodSymbol[]>();
--- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java!
+++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java!
@@ -535,6 +535,14 @@ public class TransTypes extends TreeTran
result = tree;
}
+
+
+
+
+
+
+
+
Thu Jul 15 16:31:56 2010 +0100
Fri Jul 16 19:35:24 2010 -0700
public void visitTry(JCTry tree) {
tree.resources = translate(tree.resources, syms.autoCloseableType);
tree.body = translate(tree.body);
tree.catchers = translateCatchers(tree.catchers);
tree.finalizer = translate(tree.finalizer);
result = tree;
}
public void visitConditional(JCConditional tree) {
tree.cond = translate(tree.cond, syms.booleanType);
tree.truepart = translate(tree.truepart, erasure(tree.type));
--- a/src/share/classes/com/sun/tools/javac/jvm/CRTable.java!
+++ b/src/share/classes/com/sun/tools/javac/jvm/CRTable.java!
@@ -325,6 +325,7 @@ implements CRTFlags {
public void visitTry(JCTry tree) {
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
sr.mergeWith(csp(tree.resources));
sr.mergeWith(csp(tree.body));
sr.mergeWith(cspCatchers(tree.catchers));
sr.mergeWith(csp(tree.finalizer));
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java!
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java!
@@ -131,6 +131,7 @@ public class JavacParser implements Pars
this.allowForeach = source.allowForeach();
this.allowStaticImport = source.allowStaticImport();
this.allowAnnotations = source.allowAnnotations();
+
this.allowTWR = source.allowTryWithResources();
this.allowDiamond = source.allowDiamond();
this.allowMulticatch = source.allowMulticatch();
this.allowTypeAnnotations = source.allowTypeAnnotations();
@@ -185,6 +186,10 @@ public class JavacParser implements Pars
/** Switch: should we recognize type annotations?
*/
boolean allowTypeAnnotations;
+
+
/** Switch: should we recognize automatic resource management?
+
*/
+
boolean allowTWR;
Thu Jul 15 16:31:56 2010 +0100
Fri Jul 16 19:35:24 2010 -0700
+
Thu Jul 15 16:31:56 2010 +0100
Fri Jul 16 19:35:24 2010 -0700
/** Switch: should we keep docComments?
*/
@@ -1846,6 +1851,7 @@ public class JavacParser implements Pars
*
| WHILE ParExpression Statement
*
| DO Statement WHILE ParExpression ";"
*
| TRY Block ( Catches | [Catches] FinallyPart )
+
*
| TRY "(" ResourceSpecification ")" Block [Catches] [FinallyPart]
*
| SWITCH ParExpression "{" SwitchBlockStatementGroups "}"
*
| SYNCHRONIZED ParExpression Block
*
| RETURN [Expression] ";"
@@ -1916,6 +1922,13 @@ public class JavacParser implements Pars
}
case TRY: {
S.nextToken();
+
List<JCTree> resources = List.<JCTree>nil();
+
if (S.token() == LPAREN) {
+
checkAutomaticResourceManagement();
+
S.nextToken();
+
resources = resources();
+
accept(RPAREN);
+
}
JCBlock body = block();
ListBuffer<JCCatch> catchers = new ListBuffer<JCCatch>();
JCBlock finalizer = null;
@@ -1926,9 +1939,13 @@ public class JavacParser implements Pars
finalizer = block();
}
} else {
log.error(pos, "try.without.catch.or.finally");
}
return F.at(pos).Try(body, catchers.toList(), finalizer);
+
if (allowTWR) {
+
if (resources.isEmpty())
+
log.error(pos, "try.without.catch.finally.or.resource.decls");
+
} else
+
log.error(pos, "try.without.catch.or.finally");
+
}
+
return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
}
case SWITCH: {
S.nextToken();
@@ -2387,6 +2404,39 @@ public class JavacParser implements Pars
if ((mods.flags & Flags.VARARGS) == 0)
type = bracketsOpt(type);
return toP(F.at(pos).VarDef(mods, name, type, null));
+
}
+
+
/** Resources = Resource { ";" Resources }
+
*/
+
List<JCTree> resources() {
+
ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
+
defs.append(resource());
+
while (S.token() == SEMI) {
+
// All but last of multiple declarators subsume a semicolon
+
storeEnd(defs.elems.last(), S.endPos());
+
S.nextToken();
+
defs.append(resource());
+
}
+
return defs.toList();
+
}
+
+
/** Resource =
+
*
VariableModifiers Type VariableDeclaratorId = Expression
+
* | Expression
+
*/
+
JCTree resource() {
+
int pos = S.pos();
+
if (S.token() == FINAL || S.token() == MONKEYS_AT) {
+
return variableDeclaratorRest(pos, optFinal(0), parseType(),
+
ident(), true, null);
+
} else {
+
JCExpression t = term(EXPR | TYPE);
+
if ((lastmode & TYPE) != 0 && S.token() == IDENTIFIER)
+
return variableDeclaratorRest(pos, toP(F.at(pos).Modifiers(Flags.FINAL)), t,
+
ident(), true, null);
+
else
+
return t;
+
}
}
/** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
@@ -3220,6 +3270,12 @@ public class JavacParser implements Pars
if (!allowMulticatch) {
log.error(S.pos(), "multicatch.not.supported.in.source", source.name);
allowMulticatch = true;
}
+
}
+
}
+
void checkAutomaticResourceManagement() {
+
if (!allowTWR) {
+
log.error(S.pos(), "automatic.resource.management.not.supported.in.source", source.name);
+
allowTWR = true;
+
}
}
}
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties!
Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties!
Fri Jul 16 19:35:24 2010 -0700
@@ -61,6 +61,8 @@ compiler.err.anon.class.impl.intf.no.typ
anonymous class implements interface; cannot have type arguments
compiler.err.anon.class.impl.intf.no.qual.for.new=\
anonymous class implements interface; cannot have qualifier for new
+compiler.misc.twr.not.applicable.to.type=\
+
automatic resource management not applicable to variable type
compiler.err.array.and.varargs=\
cannot declare both {0} and {1} in {2}
compiler.err.array.dimension.missing=\
@@ -172,6 +174,8 @@ compiler.err.except.never.thrown.in.try=
compiler.err.final.parameter.may.not.be.assigned=\
final parameter {0} may not be assigned
+compiler.err.twr.resource.may.not.be.assigned=\
+
automatic resource {0} may not be assigned
compiler.err.multicatch.parameter.may.not.be.assigned=\
multi-catch parameter {0} may not be assigned
compiler.err.multicatch.param.must.be.final=\
@@ -448,6 +452,8 @@ compiler.err.throws.not.allowed.in.intf.
throws clause not allowed in @interface members
compiler.err.try.without.catch.or.finally=\
''try'' without ''catch'' or ''finally''
+compiler.err.try.without.catch.finally.or.resource.decls=\
+
''try'' without ''catch'', ''finally'' or resource declarations
compiler.err.type.doesnt.take.params=\
type {0} does not take parameters
compiler.err.type.var.cant.be.deref=\
@@ -797,6 +803,10 @@ compiler.warn.proc.unmatched.processor.o
compiler.warn.proc.unmatched.processor.options=\
The following options were not recognized by any processor: ''{0}''
+compiler.warn.twr.explicit.close.call=\
+
[arm] explicit call to close() on an automatic resource
+compiler.warn.automatic.resource.not.referenced=\
+
[arm] automatic resource {0} is never referenced in body of corresponding try statement
compiler.warn.unchecked.assign=\
[unchecked] unchecked assignment: {0} to {1}
compiler.warn.unchecked.assign.to.var=\
@@ -1217,6 +1227,10 @@ compiler.err.unsupported.underscore.lit=
underscores in literals are not supported in -source {0}\n\
1
(use -source 7 or higher to enable underscores in literals)
+compiler.err.automatic.resource.management.not.supported.in.source=\
+
automatic resource management is not supported in -source {0}\n\
+(use -source 7 or higher to enable automatic resource management)
+
compiler.warn.enum.as.identifier=\
as of release 5, ''enum'' is a keyword, and may not be used as an identifier\n\
(use -source 5 or higher to use ''enum'' as a keyword)
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java!
Thu Jul
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java!
Fri Jul
@@ -1021,10 +1021,15 @@ public abstract class JCTree implements
public JCBlock body;
public List<JCCatch> catchers;
public JCBlock finalizer;
protected JCTry(JCBlock body, List<JCCatch> catchers, JCBlock finalizer) {
+
public List<JCTree> resources;
+
protected JCTry(List<JCTree> resources,
+
JCBlock body,
+
List<JCCatch> catchers,
+
JCBlock finalizer) {
this.body = body;
this.catchers = catchers;
this.finalizer = finalizer;
+
this.resources = resources;
}
@Override
public void accept(Visitor v) { v.visitTry(this); }
@@ -1038,6 +1043,10 @@ public abstract class JCTree implements
@Override
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
return v.visitTry(this, d);
+
}
+
@Override
+
public List<? extends JCTree> getResources() {
+
return resources;
}
@Override
public int getTag() {
@@ -2162,6 +2171,10 @@ public abstract class JCTree implements
JCCase Case(JCExpression pat, List<JCStatement> stats);
JCSynchronized Synchronized(JCExpression lock, JCBlock body);
JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
+
JCTry Try(List<JCTree> resources,
+
JCBlock body,
+
List<JCCatch> catchers,
+
JCBlock finalizer);
JCCatch Catch(JCVariableDecl param, JCBlock body);
JCConditional Conditional(JCExpression cond,
JCExpression thenpart,
--- a/src/share/classes/com/sun/tools/javac/tree/Pretty.java!
Thu Jul
+++ b/src/share/classes/com/sun/tools/javac/tree/Pretty.java!
Fri Jul
@@ -691,6 +691,19 @@ public class Pretty extends JCTree.Visit
public void visitTry(JCTry tree) {
try {
print("try ");
+
if (tree.resources.nonEmpty()) {
+
print("(");
+
boolean first = true;
+
for (JCTree var : tree.resources) {
+
if (!first) {
+
println();
+
indent();
+
}
+
printStat(var);
+
first = false;
+
}
+
print(") ");
+
}
printStat(tree.body);
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
printStat(l.head);
--- a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java!
Thu Jul
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java!
Fri Jul
@@ -332,10 +332,11 @@ public class TreeCopier<P> implements Tr
+
+
15 16:31:56 2010 +0100
16 19:35:24 2010 -0700
15 16:31:56 2010 +0100
16 19:35:24 2010 -0700
public JCTree visitTry(TryTree node, P p) {
JCTry t = (JCTry) node;
List<JCTree> resources = copy(t.resources, p);
JCBlock body = copy(t.body, p);
List<JCCatch> catchers = copy(t.catchers, p);
JCBlock finalizer = copy(t.finalizer, p);
return M.at(t.pos).Try(body, catchers, finalizer);
return M.at(t.pos).Try(resources, body, catchers, finalizer);
}
public JCTree visitParameterizedType(ParameterizedTypeTree node, P p) {
--- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java!
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java!
@@ -269,7 +269,14 @@ public class TreeMaker implements JCTree
}
+
+
+
+
+
+
+
+
15 16:31:56 2010 +0100
16 19:35:24 2010 -0700
Thu Jul 15 16:31:56 2010 +0100
Fri Jul 16 19:35:24 2010 -0700
public JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer) {
JCTry tree = new JCTry(body, catchers, finalizer);
return Try(List.<JCTree>nil(), body, catchers, finalizer);
}
public JCTry Try(List<JCTree> resources,
JCBlock body,
List<JCCatch> catchers,
JCBlock finalizer) {
JCTry tree = new JCTry(resources, body, catchers, finalizer);
tree.pos = pos;
return tree;
}
--- a/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java!
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java!
@@ -147,6 +147,7 @@ public class TreeScanner extends Visitor
}
public void visitTry(JCTry tree) {
scan(tree.resources);
scan(tree.body);
scan(tree.catchers);
scan(tree.finalizer);
--- a/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java!
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java!
@@ -212,6 +212,7 @@ public class TreeTranslator extends JCTr
}
Thu Jul 15 16:31:56 2010 +0100
Fri Jul 16 19:35:24 2010 -0700
+
Thu Jul 15 16:31:56 2010 +0100
Fri Jul 16 19:35:24 2010 -0700
public void visitTry(JCTry tree) {
tree.resources = translate(tree.resources);
tree.body = translate(tree.body);
tree.catchers = translateCatchers(tree.catchers);
tree.finalizer = translate(tree.finalizer);
--- a/src/share/classes/com/sun/tools/javac/util/Names.java! Thu Jul 15 16:31:56 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/util/Names.java! Fri Jul 16 19:35:24 2010 -0700
@@ -148,6 +148,8 @@ public class Names {
public final Name getDeclaringClass;
public final Name ex;
public final Name finalize;
+
public final Name java_lang_AutoCloseable;
+
public final Name close;
+
public final Name.Table table;
@@ -263,6 +265,9 @@ public class Names {
getDeclaringClass = fromString("getDeclaringClass");
ex = fromString("ex");
finalize = fromString("finalize");
+
+
java_lang_AutoCloseable = fromString("java.lang.AutoCloseable");
+
close = fromString("close");
}
protected Name.Table createTable(Options options) {
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/ArmLint.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,55 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740 6965277 6967065
+ * @author Joseph D. Darcy
+ * @summary Check that -Xlint:arm warnings are generated as expected
+ * @compile/ref=ArmLint.out -Xlint:arm,deprecation -XDrawDiagnostics ArmLint.java
+ */
+
+class ArmLint implements AutoCloseable {
+
private static void test1() {
+
try(ArmLint r1 = new ArmLint();
+
ArmLint r2 = new ArmLint();
+
ArmLint r3 = new ArmLint()) {
+
r1.close();
// The resource's close
+
r2.close(42); // *Not* the resource's close
+
// r3 not referenced
+
}
+
+
}
+
+
@SuppressWarnings("arm")
+
private static void test2() {
+
try(@SuppressWarnings("deprecation") AutoCloseable r4 =
+
new DeprecatedAutoCloseable()) {
+
// r4 not referenced
+
} catch(Exception e) {
+
;
+
}
+
}
+
+
/**
+
* The AutoCloseable method of a resource.
+
*/
+
@Override
+
public void close () {
+
return;
+
}
+
+
/**
+
* <em>Not</em> the AutoCloseable method of a resource.
Freitag, 10. Januar 14
+
*/
+
public void close (int arg) {
+
return;
+
}
+}
+
+@Deprecated
+class DeprecatedAutoCloseable implements AutoCloseable {
+
public DeprecatedAutoCloseable(){super();}
+
+
@Override
+
public void close () {
+
return;
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/ArmLint.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,3 @@
+ArmLint.java:14:15: compiler.warn.twr.explicit.close.call
+ArmLint.java:13:13: compiler.warn.automatic.resource.not.referenced: r3
+2 warnings
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/BadTwr.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,36 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740
+ * @author Joseph D. Darcy
+ * @summary Verify bad TWRs don't compile
+ * @compile/fail -source 6 TwrFlow.java
+ * @compile/fail/ref=BadTwr.out -XDrawDiagnostics BadTwr.java
+ */
+
+public class BadTwr implements AutoCloseable {
+
public static void main(String... args) {
+
// illegal repeated name
+
try(BadTwr r1 = new BadTwr(); BadTwr r1 = new BadTwr()) {
+
System.out.println(r1.toString());
+
}
+
+
// illegal duplicate name of method argument
+
try(BadTwr args = new BadTwr()) {
+
System.out.println(args.toString());
+
final BadTwr thatsIt = new BadTwr();
+
thatsIt = null;
+
}
+
+
try(BadTwr name = new BadTwr()) {
+
// illegal duplicate name of enclosing try
+
try(BadTwr name = new BadTwr()) {
+
System.out.println(name.toString());
+
}
+
}
+
+
}
+
+
public void close() {
+
;
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/BadTwr.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,5 @@
+BadTwr.java:13:39: compiler.err.already.defined: r1, main(java.lang.String...)
+BadTwr.java:18:13: compiler.err.already.defined: args, main(java.lang.String...)
+BadTwr.java:21:13: compiler.err.cant.assign.val.to.final.var: thatsIt
+BadTwr.java:26:17: compiler.err.already.defined: name, main(java.lang.String...)
+4 errors
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/BadTwrSyntax.java! Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,22 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740
+ * @author Joseph D. Darcy
+ * @summary Verify bad TWRs don't compile
+ * @compile/fail -source 6 BadTwrSyntax.java
+ * @compile/fail/ref=BadTwrSyntax.out -XDrawDiagnostics BadTwrSyntax.java
+ */
+
+import java.io.IOException;
+public class BadTwrSyntax implements AutoCloseable {
+
public static void main(String... args) throws Exception {
+
// illegal semicolon ending resources
+
try(BadTwr twrflow = new BadTwr();) {
+
System.out.println(twrflow.toString());
+
}
+
}
+
+
public void close() {
+
;
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/BadTwrSyntax.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,2 @@
+BadTwrSyntax.java:14:43: compiler.err.illegal.start.of.expr
+1 error
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/DuplicateResource.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911256 6964740 6965277
+ * @author Maurizio Cimadamore
+ * @summary Check that lowered arm block does not end up creating resource twice
+ */
+
+import java.util.ArrayList;
+
+public class DuplicateResource {
+
+
static class TestResource implements AutoCloseable {
+
TestResource() {
+
resources.add(this);
+
}
+
boolean isClosed = false;
+
public void close() throws Exception {
+
isClosed = true;
+
}
+
}
+
+
static ArrayList<TestResource> resources = new ArrayList<TestResource>();
+
+
public static void main(String[] args) {
+
try(new TestResource()) {
+
//do something
+
} catch (Exception e) {
+
throw new AssertionError("Shouldn't reach here", e);
+
}
+
check();
+
}
+
+
public static void check() {
+
if (resources.size() != 1) {
+
throw new AssertionError("Expected one resource, found: " + resources.size());
+
}
+
TestResource resource = resources.get(0);
+
if (!resource.isClosed) {
+
throw new AssertionError("Resource used in ARM block has not been automatically closed");
+
}
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/DuplicateResourceDecl.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,20 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740 6965277
+ * @author Maurizio Cimadamore
+ * @summary Check that resource variable is not accessible from catch/finally clause
+ * @compile/fail/ref=DuplicateResourceDecl.out -XDrawDiagnostics DuplicateResourceDecl.java
+ */
+
+class DuplicateResourceDecl {
+
+
public static void main(String[] args) {
+
try(MyResource c = new MyResource();MyResource c = new MyResource()) {
+
//do something
+
} catch (Exception e) { }
+
}
+
+
static class MyResource implements AutoCloseable {
+
public void close() throws Exception {}
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/DuplicateResourceDecl.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,2 @@
+DuplicateResourceDecl.java:12:45: compiler.err.already.defined: c, main(java.lang.String[])
+1 error
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/ImplicitFinal.java! Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,27 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740 6965277
+ * @author Maurizio Cimadamore
+ * @summary Test that resource variables are implicitly final
+ * @compile/fail/ref=ImplicitFinal.out -XDrawDiagnostics ImplicitFinal.java
+ */
+
+import java.io.IOException;
+
+class ImplicitFinal implements AutoCloseable {
+
public static void main(String... args) {
+
try(ImplicitFinal r = new ImplicitFinal()) {
+
r = null; //disallowed
+
} catch (IOException ioe) { // Not reachable
+
throw new AssertionError("Shouldn't reach here", ioe);
+
}
+
}
+
+
+
// A close method, but the class is <em>not</em> Closeable or
+
// AutoCloseable.
+
+
public void close() throws IOException {
+
throw new IOException();
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/ImplicitFinal.out! Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,2 @@
+ImplicitFinal.java:14:13: compiler.err.twr.resource.may.not.be.assigned: r
+1 error
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/PlainTry.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740
+ * @author Joseph D. Darcy
+ * @summary Test error messages for an unadorned try
+ * @compile/fail/ref=PlainTry6.out -XDrawDiagnostics -source 6 PlainTry.java
+ * @compile/fail/ref=PlainTry.out -XDrawDiagnostics
PlainTry.java
+ */
+public class PlainTry {
+
public static void main(String... args) {
+
try {
+
;
+
}
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/PlainTry.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,2 @@
+PlainTry.java:11:9: compiler.err.try.without.catch.finally.or.resource.decls
+1 error
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/PlainTry6.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,2 @@
+PlainTry.java:11:9: compiler.err.try.without.catch.or.finally
+1 error
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/ResourceOutsideTry.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,23 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740 6965277
+ * @author Maurizio Cimadamore
+ * @summary Check that resource variable is not accessible from catch/finally clause
+ * @compile/fail/ref=ResourceOutsideTry.out -XDrawDiagnostics ResourceOutsideTry.java
+ */
+
+class ResourceOutsideTry {
+
void test() {
+
try(MyResource c = new MyResource()) {
+
//do something
+
} catch (Exception e) {
+
c.test();
+
} finally {
+
c.test();
+
}
+
}
+
static class MyResource implements AutoCloseable {
+
public void close() throws Exception {}
+
void test() {}
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/ResourceOutsideTry.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,3 @@
+ResourceOutsideTry.java:14:13: compiler.err.cant.resolve.location: kindname.variable, c, , , kindname.class, ResourceOutsideTry
+ResourceOutsideTry.java:16:13: compiler.err.cant.resolve.location: kindname.variable, c, , , kindname.class, ResourceOutsideTry
+2 errors
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/ResourceTypeVar.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911256 6964740 6965277
+ * @author Maurizio Cimadamore
+ * @summary Resource of a type-variable type crashes Flow
+ * @compile ResourceTypeVar.java
+ */
+
+class ResourceTypeVar<X extends AutoCloseable> {
+
+
public void test() {
+
try(X armflow = getX()) {
+
//do something
+
} catch (Exception e) { // Not reachable
+
throw new AssertionError("Shouldn't reach here", e);
+
}
+
}
+
+
X getX() { return null; }
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrFlow.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,39 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740
+ * @author Joseph D. Darcy
+ * @summary Test exception analysis of ARM blocks
+ * @compile/fail/ref=TwrFlow.out -XDrawDiagnostics TwrFlow.java
+ */
+
+import java.io.IOException;
+public class TwrFlow implements AutoCloseable {
+
public static void main(String... args) {
+
try(TwrFlow armflow = new TwrFlow()) {
+
System.out.println(armflow.toString());
+
} catch (IOException ioe) { // Not reachable
+
throw new AssertionError("Shouldn't reach here", ioe);
+
}
+
// CustomCloseException should be caught or added to throws clause
+
+
// Also check behavior on a resource expression rather than a
+
// declaration.
+
TwrFlow armflowexpr = new TwrFlow();
+
try(armflowexpr) {
+
System.out.println(armflowexpr.toString());
+
} catch (IOException ioe) { // Not reachable
+
throw new AssertionError("Shouldn't reach here", ioe);
+
}
+
// CustomCloseException should be caught or added to throws clause
+
}
+
+
/*
+
* A close method, but the class is <em>not</em> Closeable or
+
* AutoCloseable.
+
*/
+
public void close() throws CustomCloseException {
+
throw new CustomCloseException();
+
}
+}
+
+class CustomCloseException extends Exception {}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrFlow.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,5 @@
+TwrFlow.java:14:11: compiler.err.except.never.thrown.in.try: java.io.IOException
+TwrFlow.java:24:11: compiler.err.except.never.thrown.in.try: java.io.IOException
+TwrFlow.java:12:46: compiler.err.unreported.exception.need.to.catch.or.throw: CustomCloseException
+TwrFlow.java:22:26: compiler.err.unreported.exception.need.to.catch.or.throw: CustomCloseException
+4 errors
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrInference.java! Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911256 6964740 6965277
+ * @author Maurizio Cimadamore
+ * @summary Verify that method type-inference works as expected in TWR context
+ * @compile TwrInference.java
+ */
+
+class TwrInference {
+
+
public void test() {
+
try(getX()) {
+
//do something
+
} catch (Exception e) { // Not reachable
+
throw new AssertionError("Shouldn't reach here", e);
+
}
+
}
+
+
<X> X getX() { return null; }
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrIntersection.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911256 6964740 6965277
+ * @author Maurizio Cimadamore
+ * @summary Resource of an intersection type crashes Flow
+ * @compile TwrIntersection.java
+ */
+
+interface MyCloseable extends AutoCloseable {
+
void close() throws java.io.IOException;
+}
+
+class ResourceTypeVar {
+
+
public void test() {
+
try(getX()) {
+
//do something
+
} catch (java.io.IOException e) { // Not reachable
+
throw new AssertionError("Shouldn't reach here", e);
+
}
+
}
+
+
<X extends Number & MyCloseable> X getX() { return null; }
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrIntersection02.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,37 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740 6965277
+ * @author Maurizio Cimadamore
+ * @summary Check that resources of an intersection type forces union of exception types
+ *
to be caught outside twr block
+ * @compile/fail/ref=TwrIntersection02.out -XDrawDiagnostics TwrIntersection02.java
+ */
+
+class TwrIntersection02 {
+
+
static class Exception1 extends Exception {}
+
static class Exception2 extends Exception {}
+
+
+
interface MyResource1 extends AutoCloseable {
+
void close() throws Exception1;
+
}
+
+
interface MyResource2 extends AutoCloseable {
+
void close() throws Exception2;
+
}
+
+
public void test1() throws Exception1 {
+
try(getX()) {
+
//do something
+
}
+
}
+
+
public void test2() throws Exception2 {
+
try(getX()) {
+
//do something
+
}
+
}
+
+
<X extends MyResource1 & MyResource2> X getX() { return null; }
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrIntersection02.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,3 @@
+TwrIntersection02.java:25:21: compiler.err.unreported.exception.need.to.catch.or.throw: TwrIntersection02.Exception2
+TwrIntersection02.java:31:21: compiler.err.unreported.exception.need.to.catch.or.throw: TwrIntersection02.Exception1
+2 errors
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrMultiCatch.java! Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911256 6964740
+ * @author Joseph D. Darcy
+ * @summary Test that TWR and multi-catch play well together
+ * @compile TwrMultiCatch.java
+ * @run main TwrMultiCatch
+ */
+
2
+import java.io.IOException;
+public class TwrMultiCatch implements AutoCloseable {
+
private final Class<? extends Exception> exceptionClass;
+
+
private TwrMultiCatch(Class<? extends Exception> exceptionClass) {
+
this.exceptionClass = exceptionClass;
+
}
+
+
public static void main(String... args) {
+
test(new TwrMultiCatch(CustomCloseException1.class),
+
CustomCloseException1.class);
+
+
test(new TwrMultiCatch(CustomCloseException2.class),
+
CustomCloseException2.class);
+
}
+
+
private static void test(TwrMultiCatch twrMultiCatch,
+
Class<? extends Exception> expected) {
+
try(twrMultiCatch) {
+
System.out.println(twrMultiCatch.toString());
+
} catch (final CustomCloseException1 |
+
CustomCloseException2 exception) {
+
if (!exception.getClass().equals(expected) ) {
+
throw new RuntimeException("Unexpected catch!");
+
}
+
}
+
}
+
+
public void close() throws CustomCloseException1, CustomCloseException2 {
+
Throwable t;
+
try {
+
t = exceptionClass.newInstance();
+
} catch(ReflectiveOperationException rfe) {
+
throw new RuntimeException(rfe);
+
}
+
+
try {
+
throw t;
+
} catch (final CustomCloseException1 |
+
CustomCloseException2 exception) {
+
throw exception;
+
} catch (Throwable throwable) {
+
throw new RuntimeException(throwable);
+
}
+
}
+}
+
+class CustomCloseException1 extends Exception {}
+class CustomCloseException2 extends Exception {}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrOnNonResource.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,42 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6911256 6964740
+ * @author Joseph D. Darcy
+ * @summary Verify invalid TWR block is not accepted.
+ * @compile/fail -source 6 TwrOnNonResource.java
+ * @compile/fail/ref=TwrOnNonResource.out -XDrawDiagnostics TwrOnNonResource.java
+ */
+
+class TwrOnNonResource {
+
public static void main(String... args) {
+
try(TwrOnNonResource aonr = new TwrOnNonResource()) {
+
System.out.println(aonr.toString());
+
}
+
try(TwrOnNonResource aonr = new TwrOnNonResource()) {
+
System.out.println(aonr.toString());
+
} finally {;}
+
try(TwrOnNonResource aonr = new TwrOnNonResource()) {
+
System.out.println(aonr.toString());
+
} catch (Exception e) {;}
+
+
// Also check expression form
+
TwrOnNonResource aonr = new TwrOnNonResource();
+
try(aonr) {
+
System.out.println(aonr.toString());
+
}
+
try(aonr) {
+
System.out.println(aonr.toString());
+
} finally {;}
+
try(aonr) {
+
System.out.println(aonr.toString());
+
} catch (Exception e) {;}
+
}
+
+
/*
+
* A close method, but the class is <em>not</em> Closeable or
+
* AutoCloseable.
+
*/
+
public void close() {
+
throw new AssertionError("I'm not Closable!");
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrOnNonResource.out!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,7 @@
+TwrOnNonResource.java:12:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource,
+TwrOnNonResource.java:15:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource,
+TwrOnNonResource.java:18:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource,
+TwrOnNonResource.java:24:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource,
+TwrOnNonResource.java:27:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource,
+TwrOnNonResource.java:30:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource,
+6 errors
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/TwrTests.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911256 6964740
+ * @summary Tests of generated TWR code.
+ */
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class TwrTests {
+
public static void main(String[] args) {
+
testCreateFailure1();
+
testCreateFailure2();
+
testCreateFailure2Nested();
+
testCreateFailure3();
+
testCreateFailure3Nested();
+
testCreateFailure4();
+
testCreateFailure4Nested();
+
testCreateFailure5();
+
testCreateFailure5Nested();
+
+
testCreateSuccess1();
+
testCreateSuccess2();
+
testCreateSuccess2Nested();
+
testCreateSuccess3();
+
testCreateSuccess3Nested();
+
testCreateSuccess4();
+
testCreateSuccess4Nested();
+
testCreateSuccess5();
+
testCreateSuccess5Nested();
+
}
+
+
/*
+
* The following tests simulate a creation failure of every possible
+
* resource in an TWR block, and check to make sure that the failure
+
* prevents creation of subsequent resources, and that all created
+
* resources are properly closed, even if one or more of the close
+
* attempts fails.
+
*/
+
+
public static void testCreateFailure1() {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>(0);
+
try (Resource r0 = createResource(0, 0, 0, closedList)) {
+
throw new AssertionError("Resource creation succeeded");
+
} catch (Resource.CreateFailException e) {
+
creationFailuresDetected++;
+
if (e.resourceId() != 0) {
+
throw new AssertionError("Wrong resource creation "
+
+ e.resourceId() + " failed");
+
}
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Unexpected CloseFailException: " + e.resourceId());
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, 0);
+
}
+
Freitag, 10. Januar 14
+
public static void testCreateFailure2() {
+
for (int createFailureId = 0; createFailureId < 2; createFailureId++) {
+
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList);
+
Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
+
throw new AssertionError("Entire resource creation succeeded");
+
} catch (Resource.CreateFailException e) {
+
creationFailuresDetected++;
+
checkCreateFailureId(e.resourceId(), createFailureId);
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Secondary exception suppression failed");
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, createFailureId);
+
}
+
}
+
}
+
+
public static void testCreateFailure2Nested() {
+
for (int createFailureId = 0; createFailureId < 2; createFailureId++) {
+
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) {
+
try(Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
+
throw new AssertionError("Entire resource creation succeeded");
+
}
+
} catch (Resource.CreateFailException e) {
+
creationFailuresDetected++;
+
checkCreateFailureId(e.resourceId(), createFailureId);
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Secondary exception suppression failed");
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, createFailureId);
+
}
+
}
+
}
+
+
public static void testCreateFailure3() {
+
for (int createFailureId = 0; createFailureId < 3; createFailureId++) {
+
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList);
+
Resource r1 = createResource(1, createFailureId, bitMap, closedList);
+
Resource r2 = createResource(2, createFailureId, bitMap, closedList)) {
+
throw new AssertionError("Entire resource creation succeeded");
+
} catch (Resource.CreateFailException e) {
+
creationFailuresDetected++;
+
checkCreateFailureId(e.resourceId(), createFailureId);
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Secondary exception suppression failed:" + e);
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, createFailureId);
+
}
+
}
+
}
+
+
public static void testCreateFailure3Nested() {
+
for (int createFailureId = 0; createFailureId < 3; createFailureId++) {
+
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) {
+
try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
+
try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) {
+
throw new AssertionError("Entire resource creation succeeded");
+
}
+
}
+
} catch (Resource.CreateFailException e) {
+
creationFailuresDetected++;
+
checkCreateFailureId(e.resourceId(), createFailureId);
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Secondary exception suppression failed:" + e);
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, createFailureId);
+
}
+
}
+
}
+
+
public static void testCreateFailure4() {
+
for (int createFailureId = 0; createFailureId < 4; createFailureId++) {
+
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList);
+
Resource r1 = createResource(1, createFailureId, bitMap, closedList);
+
Resource r2 = createResource(2, createFailureId, bitMap, closedList);
+
Resource r3 = createResource(3, createFailureId, bitMap, closedList)) {
java.lang.AutoCloseable
+
throw new AssertionError("Entire resource creation succeeded");
java.lang.AutoCloseable
+
} catch (Resource.CreateFailException e) {
java.lang.AutoCloseable
+
creationFailuresDetected++;
java.lang.AutoCloseable
+
checkCreateFailureId(e.resourceId(), createFailureId);
java.lang.AutoCloseable
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
java.lang.AutoCloseable
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Secondary exception suppression failed:" + e);
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, createFailureId);
+
}
+
}
+
}
+
+
public static void testCreateFailure4Nested() {
+
for (int createFailureId = 0; createFailureId < 4; createFailureId++) {
+
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) {
+
try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
+
try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) {
+
try (Resource r3 = createResource(3, createFailureId, bitMap, closedList)) {
+
throw new AssertionError("Entire resource creation succeeded");
+
}
+
}
+
}
+
} catch (Resource.CreateFailException e) {
+
creationFailuresDetected++;
+
checkCreateFailureId(e.resourceId(), createFailureId);
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Secondary exception suppression failed:" + e);
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, createFailureId);
+
}
+
}
+
}
+
+
public static void testCreateFailure5() {
+
for (int createFailureId = 0; createFailureId < 5; createFailureId++) {
+
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList);
+
Resource r1 = createResource(1, createFailureId, bitMap, closedList);
+
Resource r2 = createResource(2, createFailureId, bitMap, closedList);
+
Resource r3 = createResource(3, createFailureId, bitMap, closedList);
+
Resource r4 = createResource(4, createFailureId, bitMap, closedList)) {
+
throw new AssertionError("Entire resource creation succeeded");
+
} catch (Resource.CreateFailException e) {
+
creationFailuresDetected++;
+
checkCreateFailureId(e.resourceId(), createFailureId);
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Secondary exception suppression failed:" + e);
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, createFailureId);
+
}
+
}
+
}
+
+
public static void testCreateFailure5Nested() {
+
for (int createFailureId = 0; createFailureId < 5; createFailureId++) {
+
for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) {
+
int creationFailuresDetected = 0;
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) {
+
try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) {
+
try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) {
+
try (Resource r3 = createResource(3, createFailureId, bitMap, closedList)) {
+
try (Resource r4 = createResource(4, createFailureId, bitMap, closedList)) {
+
throw new AssertionError("Entire resource creation succeeded");
+
}
+
}
+
}
+
}
+
} catch (Resource.CreateFailException e) {
+
creationFailuresDetected++;
+
checkCreateFailureId(e.resourceId(), createFailureId);
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
+
} catch (Resource.CloseFailException e) {
+
throw new AssertionError("Secondary exception suppression failed:" + e);
+
}
+
checkForSingleCreationFailure(creationFailuresDetected);
+
checkClosedList(closedList, createFailureId);
+
}
+
}
+
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/**
* Create a resource with the specified ID. The ID must be less than createFailureId.
* A subsequent attempt to close the resource will fail iff the corresponding bit
* is set in closeFailureBitMap. When an attempt is made to close this resource,
* its ID will be added to closedList, regardless of whether the attempt succeeds.
*
* @param id the ID of this resource
* @param createFailureId the ID of the resource whose creation will fail
* @param closeFailureBitMap a bit vector describing which resources should throw an
*
exception when close is attempted
* @param closedList a list on which to record resource close attempts
* @throws AssertionError if no attempt should be made to create this resource
*/
private static Resource createResource(int id,
int createFailureId,
int closeFailureBitMap,
List<Integer> closedList) throws Resource.CreateFailException {
if (id > createFailureId)
throw new AssertionError("Resource " + id + " shouldn't be created");
boolean createSucceeds = id != createFailureId;
boolean closeSucceeds = (closeFailureBitMap & (1 << id)) == 0;
return new Resource(id, createSucceeds, closeSucceeds, closedList);
}
/**
* Check that an observed creation failure has the expected resource ID.
*
* @param foundId the ID of the resource whose creation failed
* @param expectedId the ID of the resource whose creation should have failed
*/
private static void checkCreateFailureId(int foundId, int expectedId) {
if (foundId != expectedId)
throw new AssertionError("Wrong resource creation failed. Found ID "
+ foundId + " expected " + expectedId);
}
/**
* Check for proper suppressed exceptions in proper order.
*
* @param suppressedExceptions the suppressed exceptions array returned by
*
getSuppressedExceptions()
* @bitmap a bitmap indicating which suppressed exceptions are expected.
*
Bit i is set iff id should throw a CloseFailException.
*/
private static void checkSuppressedExceptions(Throwable[] suppressedExceptions, int bitMap) {
if (suppressedExceptions.length != Integer.bitCount(bitMap))
throw new AssertionError("Expected " + Integer.bitCount(bitMap)
+ " suppressed exceptions, got " + suppressedExceptions.length);
int prevCloseFailExceptionId = Integer.MAX_VALUE;
for (Throwable t : suppressedExceptions) {
int id = ((Resource.CloseFailException) t).resourceId();
if ((1 << id & bitMap) == 0)
throw new AssertionError("Unexpected suppressed CloseFailException: " + id);
if (id > prevCloseFailExceptionId)
throw new AssertionError("Suppressed CloseFailException" + id
+ " followed " + prevCloseFailExceptionId);
}
}
/**
* Check that exactly one resource creation failed.
*
* @param numCreationFailuresDetected the number of creation failures detected
*/
private static void checkForSingleCreationFailure(int numCreationFailuresDetected) {
if (numCreationFailuresDetected != 1)
throw new AssertionError("Wrong number of creation failures: "
+ numCreationFailuresDetected);
}
/**
* Check that a close was attempted on every resourced that was successfully opened,
* and that the close attempts occurred in the proper order.
*
* @param closedList the resource IDs of the close attempts, in the order they occurred
* @param the ID of the resource whose creation failed. Close attempts should occur
*
for all previous resources, in reverse order.
*/
private static void checkClosedList(List<Integer> closedList, int createFailureId) {
List<Integer> expectedList = new ArrayList<Integer>(createFailureId);
for (int i = createFailureId - 1; i >= 0; i--)
expectedList.add(i);
if (!closedList.equals(expectedList))
throw new AssertionError("Closing sequence " + closedList + " != " + expectedList);
}
/*
* The following tests simulate the creation of several resources, followed
* by success or failure of forward processing. They test that all resources
* are properly closed, even if one or more of the close attempts fails.
*/
public static void testCreateSuccess1() {
for (int bitMap = 0, n = 1 << 1; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 1);
}
}
}
public static void testCreateSuccess2() {
for (int bitMap = 0, n = 1 << 2; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList);
Resource r1 = createResource(1, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 2);
}
}
}
public static void testCreateSuccess2Nested() {
for (int bitMap = 0, n = 1 << 2; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
try (Resource r1 = createResource(1, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
}
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 2);
}
}
}
public static void testCreateSuccess3() {
for (int bitMap = 0, n = 1 << 3; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList);
Resource r1 = createResource(1, bitMap, closedList);
Resource r2 = createResource(2, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 3);
}
}
}
public static void testCreateSuccess3Nested() {
for (int bitMap = 0, n = 1 << 3; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
try (Resource r1 = createResource(1, bitMap, closedList)) {
try (Resource r2 = createResource(2, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
}
}
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 3);
}
}
}
public static void testCreateSuccess4() {
for (int bitMap = 0, n = 1 << 4; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList);
Resource r1 = createResource(1, bitMap, closedList);
Resource r2 = createResource(2, bitMap, closedList);
Resource r3 = createResource(3, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 4);
}
}
}
public static void testCreateSuccess4Nested() {
for (int bitMap = 0, n = 1 << 4; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList)) {
try (Resource r1 = createResource(1, bitMap, closedList)) {
try (Resource r2 = createResource(2, bitMap, closedList)) {
try (Resource r3 = createResource(3, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
}
}
}
} catch (Resource.CreateFailException e) {
throw new AssertionError(
"Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 4);
}
}
}
public static void testCreateSuccess5() {
for (int bitMap = 0, n = 1 << 5; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
List<Integer> closedList = new ArrayList<Integer>();
try (Resource r0 = createResource(0, bitMap, closedList);
Resource r1 = createResource(1, bitMap, closedList);
Resource r2 = createResource(2, bitMap, closedList);
Resource r3 = createResource(3, bitMap, closedList);
Resource r4 = createResource(4, bitMap, closedList)) {
if (failure != 0)
throw new MyKindOfException();
} catch (Resource.CreateFailException e) {
throw new AssertionError("Resource creation failed: " + e.resourceId());
} catch (MyKindOfException e) {
if (failure == 0)
throw new AssertionError("Unexpected MyKindOfException");
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
} catch (Resource.CloseFailException e) {
if (failure == 1)
throw new AssertionError("Secondary exception suppression failed");
int id = e.resourceId();
if (bitMap == 0)
throw new AssertionError("Unexpected CloseFailException: " + id);
int highestCloseFailBit = Integer.highestOneBit(bitMap);
if (1 << id != highestCloseFailBit) {
throw new AssertionError("CloseFailException: got id " + id
+ ", expected lg(" + highestCloseFailBit +")");
}
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
}
checkClosedList(closedList, 5);
}
}
}
public static void testCreateSuccess5Nested() {
for (int bitMap = 0, n = 1 << 5; bitMap < n; bitMap++) {
for (int failure = 0; failure < 2; failure++) {
3
+
List<Integer> closedList = new ArrayList<Integer>();
+
try (Resource r0 = createResource(0, bitMap, closedList)) {
+
try (Resource r1 = createResource(1, bitMap, closedList)) {
+
try (Resource r2 = createResource(2, bitMap, closedList)) {
+
try (Resource r3 = createResource(3, bitMap, closedList)) {
+
try (Resource r4 = createResource(4, bitMap, closedList)) {
+
if (failure != 0)
+
throw new MyKindOfException();
+
}
+
}
+
}
+
}
+
} catch (Resource.CreateFailException e) {
+
throw new AssertionError("Resource creation failed: " + e.resourceId());
+
} catch (MyKindOfException e) {
+
if (failure == 0)
+
throw new AssertionError("Unexpected MyKindOfException");
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap);
+
} catch (Resource.CloseFailException e) {
+
if (failure == 1)
+
throw new AssertionError("Secondary exception suppression failed");
+
int id = e.resourceId();
+
if (bitMap == 0)
+
throw new AssertionError("Unexpected CloseFailException: " + id);
+
int highestCloseFailBit = Integer.highestOneBit(bitMap);
+
if (1 << id != highestCloseFailBit) {
+
throw new AssertionError("CloseFailException: got id " + id
+
+ ", expected lg(" + highestCloseFailBit +")");
+
}
+
checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit);
+
}
+
checkClosedList(closedList, 5);
+
}
+
}
+
}
+
+
private static Resource createResource(int id,
+
int closeFailureBitMap,
+
List<Integer> closedList) throws Resource.CreateFailException {
+
boolean closeSucceeds = (closeFailureBitMap & (1 << id)) == 0;
+
return new Resource(id, true, closeSucceeds, closedList);
+
}
+
+
private static class MyKindOfException extends Exception {
+
}
+}
+
+class Resource implements AutoCloseable {
+
/** A number identifying this resource */
+
private final int resourceId;
+
+
/** Whether the close call on this resource should succeed or fail */
+
private final boolean closeSucceeds;
+
+
/** When resource is closed, it records its ID in this list */
+
private final List<Integer> closedList;
+
+
Resource(int resourceId, boolean createSucceeds, boolean closeSucceeds,
+
List<Integer> closedList) throws CreateFailException {
+
if (!createSucceeds)
+
throw new CreateFailException(resourceId);
+
this.resourceId = resourceId;
+
this.closeSucceeds = closeSucceeds;
+
this.closedList = closedList;
+
}
+
+
public void close() throws CloseFailException {
+
closedList.add(resourceId);
+
if (!closeSucceeds)
+
throw new CloseFailException(resourceId);
+
}
+
+
public static class ResourceException extends RuntimeException {
+
private final int resourceId;
+
+
public ResourceException(int resourceId) {
+
super("Resource ID = " + resourceId);
+
this.resourceId = resourceId;
+
}
+
+
public int resourceId() {
+
return resourceId;
+
}
+
}
+
+
public static class CreateFailException extends ResourceException {
+
public CreateFailException(int resourceId) {
+
super(resourceId);
+
}
+
}
+
+
public static class CloseFailException extends ResourceException {
+
public CloseFailException(int resourceId) {
+
super(resourceId);
+
}
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/TryWithResources/WeirdTwr.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911256 6964740
+ * @author Joseph D. Darcy
+ * @summary Strange TWRs
+ * @compile/fail -source 6 WeirdTwr.java
+ * @compile WeirdTwr.java
+ * @run main WeirdTwr
+ */
+
+public class WeirdTwr implements AutoCloseable {
+
private static int closeCount = 0;
+
public static void main(String... args) {
+
try(WeirdTwr r1 = new WeirdTwr(); WeirdTwr r2 = r1) {
+
if (r1 != r2)
+
throw new RuntimeException("Unexpected inequality.");
+
}
+
if (closeCount != 2)
+
throw new RuntimeException("bad closeCount" + closeCount);
+
}
+
+
public void close() {
+
closeCount++;
+
}
+}
--- /dev/null!
Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/processing/model/element/TestResourceVariable.java!
Fri Jul 16 19:35:24 2010 -0700
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911256 6964740
+ * @summary Test that the resource variable kind is appropriately set
+ * @author Joseph D. Darcy
+ * @build TestResourceVariable
+ * @compile/fail -processor TestResourceVariable -proc:only TestResourceVariable.java
+ */
+
+// Bug should be filed for this misbehavior
+
+
Freitag, 10. Januar 14
import java.io.*;
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.lang.model.util.*;
+import java.util.*;
+import com.sun.source.tree.*;
+import com.sun.source.util.*;
+import static javax.tools.Diagnostic.Kind.*;
+
+/**
+ * Using the tree API, retrieve element representations of the
+ * resource of an ARM block and verify their kind tags are set
+ * appropriately.
+ */
+@SupportedAnnotationTypes("*")
+public class TestResourceVariable extends AbstractProcessor implements AutoCloseable {
+
int resourceVariableCount = 0;
+
+
public boolean process(Set<? extends TypeElement> annotations,
+
RoundEnvironment roundEnv) {
+
if (!roundEnv.processingOver()) {
+
Trees trees = Trees.instance(processingEnv);
+
+
for(Element rootElement : roundEnv.getRootElements()) {
+
TreePath treePath = trees.getPath(rootElement);
+
+
(new ResourceVariableScanner(trees)).
+
scan(trees.getTree(rootElement),
+
treePath.getCompilationUnit());
+
}
+
if (resourceVariableCount != 3)
+
throw new RuntimeException("Bad resource variable count " +
+
resourceVariableCount);
+
}
+
return true;
+
}
+
+
@Override
+
public void close() {}
+
+
private void test1() {
+
try(TestResourceVariable trv = this) {}
+
}
+
+
private void test2() {
+
try(TestResourceVariable trv1 = this; TestResourceVariable trv2 = trv1) {}
+
}
+
+
class ResourceVariableScanner extends TreeScanner<Void, CompilationUnitTree> {
+
private Trees trees;
+
+
public ResourceVariableScanner(Trees trees) {
+
super();
+
this.trees = trees;
+
}
+
@Override
+
public Void visitVariable(VariableTree node, CompilationUnitTree cu) {
+
Element element = trees.getElement(trees.getPath(cu, node));
+
if (element == null) {
+
System.out.println("Null variable element: " + node);
+
} else {
+
System.out.println("Name: " + element.getSimpleName() +
+
"\tKind: " + element.getKind());
+
}
+
if (element != null &&
+
element.getKind() == ElementKind.RESOURCE_VARIABLE) {
+
resourceVariableCount++;
+
}
+
return super.visitVariable(node, cu);
+
}
+
}
+
+
@Override
+
public SourceVersion getSupportedSourceVersion() {
+
return SourceVersion.latest();
+
}
+}
4
So you want to change the Clojure Programming Language...
By Jens on Jan 9, 2013
Step 1: Write a Macro
Step 2: There is no Step 2
Freitag, 10. Januar 14
Clojure
(defmacro with-resource [binding close-fn & body]
`(let ~binding
(try (do ~@body) (finally (~close-fn ~(binding 0))))))
Freitag, 10. Januar 14
Deep walking
• Bisher: "Oberflächen Macros"
• Modifikation der Top Form
• Es gibt auch Deep Walking Macros (DWM),
die die Sprache radikaler ändern
• In Clojure kann man Dinge als Bibliothek
ausliefern, die in anderen Sprachen nur
durch Sprachänderung möglich sind
Freitag, 10. Januar 14
Deep Walking Macros
Beispiel: Incanter Infix
user=> (use 'incanter.core)
nil
user=> ($= (2 + 3) * 4)
20
user=> ($= 4 * (2 + 3))
20
user=> ($= 2 + 3 * 4)
14
user=> (macroexpand-1 '($= (2 + 3) * 4))
(incanter.core/mult (incanter.core/plus 2 3) 4)
user=> (macroexpand-1 '($= 4 * (2 + 3)))
(incanter.core/mult 4 (incanter.core/plus 2 3))
user=> (macroexpand-1 '($= 2 + 3 * 4))
(incanter.core/plus 2 (incanter.core/mult 3 4))
Freitag, 10. Januar 14
Deep Walking Macros
Beispiel: core.async
• CSP Implementierung
• Von der Go Sprache adaptiert
• Idee: Prozesse kommunizieren über Channel
user=> (def c (chan))
#'user/c
user=> (go (while true (let [v (<! c)] (println "got" v))))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@1416e4cd>
user=> (go (>! c 10))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@42e80f7>
got 10
Freitag, 10. Januar 14
Deep Walking Macros
• Vorteile von core.async
- Leichtgewichtige Threads
- Funktioniert auch in ClojureScript
(d.h. ohne OS Threads)
- Eliminiert Callback Hell in ClojureScript
- Ermöglicht simplere Architektur durch Trennung
von Komponenten
• Versucht das als Bibliothek in einer anderen
Sprache zu schreiben!
Freitag, 10. Januar 14
Deep Walking Macros
Das go Macro expandiert:
user=> (pprint (macroexpand-1 '(go (>! c 10))))
Freitag, 10. Januar 14
Deep Walking Macros
user=> (pprint (macroexpand-1 '(go (>! c 10))))
(clojure.core/let
[c__2197__auto__
(clojure.core.async/chan 1)
captured-bindings__2198__auto__
(clojure.lang.Var/getThreadBindingFrame)]
(clojure.core.async.impl.dispatch/run
(clojure.core/fn
[]
(clojure.core/let
[f__2199__auto__
(clojure.core/fn
state-machine__2062__auto__
([]
(clojure.core.async.impl.ioc-macros/aset-all!
(java.util.concurrent.atomic.AtomicReferenceArray. 7)
0
state-machine__2062__auto__
1
1))
([state_4309]
(clojure.core/let
[old-frame__2063__auto__
(clojure.lang.Var/getThreadBindingFrame)
ret-value__2064__auto__
(try
(clojure.lang.Var/resetThreadBindingFrame
(clojure.core.async.impl.ioc-macros/aget-object
state_4309
3))
(clojure.core/loop
[]
(clojure.core/let
[result__2065__auto__
(clojure.core/case
(clojure.core/int
(clojure.core.async.impl.ioc-macros/aget-object
state_4309
1))
(clojure.core.async.impl.ioc-macros/aset-all!
clojure.core.async.impl.ioc-macros/USER-START-IDX
c__2197__auto__
clojure.core.async.impl.ioc-macros/BINDINGS-IDX
captured-bindings__2198__auto__))]
(clojure.core.async.impl.ioc-macros/run-state-machine-wrapped
state__2200__auto__))))
c__2197__auto__)
Freitag, 10. Januar 14
2
(clojure.core/let
[inst_4307
(clojure.core.async.impl.ioc-macros/aget-object
state_4309
2)
state_4309
state_4309]
(clojure.core.async.impl.ioc-macros/return-chan
state_4309
inst_4307))
1
(clojure.core/let
[state_4309 state_4309]
(clojure.core.async.impl.ioc-macros/put!
state_4309
2
c
10)))]
(if
(clojure.core/identical? result__2065__auto__ :recur)
(recur)
result__2065__auto__)))
(catch
java.lang.Throwable
ex__2066__auto__
(clojure.core.async.impl.ioc-macros/aset-all!
state_4309
clojure.core.async.impl.ioc-macros/CURRENT-EXCEPTION
ex__2066__auto__)
(clojure.core.async.impl.ioc-macros/process-exception
state_4309)
:recur)
(finally
(clojure.lang.Var/resetThreadBindingFrame
old-frame__2063__auto__)))]
(if
(clojure.core/identical? ret-value__2064__auto__ :recur)
(recur state_4309)
ret-value__2064__auto__))))
state__2200__auto__
(clojure.core/->
(f__2199__auto__)
DWM Implementierung
• Macros sind hart, DWM sind härter
• Es ist schwer DWM korrekt zu implementieren
• DWM erfordern Erfahrung
DWM:
http://blog.fogus.me/2013/07/17/an-introduction-to-deep-code-walking-macros-with-clojure/
http://www.youtube.com/watch?v=HXfDK1OYpco
core.async DWM:
http://www.youtube.com/watch?v=R3PZMIwXN_g
http://www.youtube.com/watch?v=SI7qtuuahhU
Freitag, 10. Januar 14
Macros
• Macros erlauben es die Sprache zu
modifizieren
• ... in potentiell radikaler Weise
• ... ohne auf Rich Hickey warten zu müssen
• Macros werden durch Homoikonizität viel
einfacher!
Freitag, 10. Januar 14
Freitag, 10. Januar 14
Haskell
Freitag, 10. Januar 14
Noch eine Sprache?
• Für die Klausur:
Es werden keine Aufgaben kommen in denen
Haskell Code geschrieben werden muss
• Das heisst nicht, dass nichts über Haskell in
der Klausur drankommt!
Freitag, 10. Januar 14
Freitag, 10. Januar 14
Freitag, 10. Januar 14
Agenda
• Typisierung
• Currying
• Pattern Matching
• Lazyness
• Functors, Applicatives & Monads
Freitag, 10. Januar 14
Typisierung
Freitag, 10. Januar 14
Typsysteme
Freitag, 10. Januar 14
stark
schwach
dynamisch
Clojure, Python
PHP
statisch
Scala,
Haskell,
Java
C
Statische Typisierung
"Static Typing is an academical experiment
only suitable for small projects."
(Stuart Halloway, Euroclojure 2013)
Freitag, 10. Januar 14
Dynamic vs. Static
user=> (defn bumm! [x] (+ "ab" 3 x))
#'user/bumm!
user=> (bumm! 1)
ClassCastException java.lang.String cannot be cast
to java.lang.Number clojure.lang.Numbers.add (Numbers.java:126)
Prelude> let bumm! x = "ab" + 3 + x
<interactive>:35:24:
No instance for (Num [Char]) arising from a use of `+'
Possible fix: add an instance declaration for (Num [Char])
In the expression: "ab" + 3 + x
In an equation for `!': bumm ! x = "ab" + 3 + x
Freitag, 10. Januar 14
Static Typing
• Vorteil: Eine gewisse Klasse von Fehlern
werden vom Compiler erkannt
• Gegenargument:
• Die Fehler sind einfach durch Testing zu
vermeiden (Python Fans)
• Es sind nur triviale Fehler (Stu Halloway)
Freitag, 10. Januar 14
Haskell Types
Prelude> :t 'a'
'a' :: Char
Prelude> :t ('1',True,"hallo")
('1',True,"hallo") :: (Char, Bool, [Char])
Prelude> :t head
head :: [a] -> a
Prelude> :t (+)
(+) :: Num a => a -> a -> a
primitives
composites
polymorphic
typeclass
Prelude> :t 5
5 :: Num a => a
Prelude> :t putStr
putStr :: String -> IO ()
Prelude Data.Maybe> :t listToMaybe
listToMaybe :: [a] -> Maybe a
Freitag, 10. Januar 14
monadic
Typinferenz
• In Haskell muss man bis auf wenige
Ausnahmen keine Typen angeben
• Typen werden vom Compiler inferiert
• Es gehört aber besonders bei Bibliotheken
zum guten Ton eine Typdeklaration zu
schreiben
myPlus :: Num a => a -> a -> a
myPlus = (+)
Freitag, 10. Januar 14
Algebraische Datentypen
• Definition eigener Datentypen geht mit data
• Bsp:
data MyBool = T | F
:t F
F :: MyBool
• MyBool ist ein Typ
• T und F nennt man value constructor
Freitag, 10. Januar 14
Algebraische Datentypen
• Es gibt auch algebraische Datentypen, die
Parameter haben
• Bsp:
data MyInt = Wert Int | Unendlich
Prelude> :t Wert 4
Wert 4 :: MyInt
Prelude> :t Wert
Wert :: Int -> MyInt
Prelude> :t Unendlich
Unendlich :: MyInt
Freitag, 10. Januar 14
Polymorphismus
Prelude> :t head
head :: [a] -> a
Prelude> head [1,2,3]
1
Prelude> head ["1","2","3"]
"1"
Prelude> head [1,2,"3"]
user=> (first [1 2 3])
1
user=> (first ["1" "2" "3"])
"1"
user=> (first [1 2 "3"])
1
<interactive>:10:7:
No instance for (Num [Char])
arising from the literal `1'
Possible fix: add an instance declaration for (Num [Char])
In the expression: 1
In the first argument of `head', namely `[1, 2, "3"]'
In the expression: head [1, 2, "3"]
Freitag, 10. Januar 14
Polymorphismus
• Die head Funktion ist polymorph
• Aber die Elemente der Liste müssen einen
gemeinsamen Typ haben
Freitag, 10. Januar 14
Übung
Welche Funktionen haben die Signaturen:
•
(a,b) -> b
•
[a] -> [a]
Freitag, 10. Januar 14
Algebraische Datentypen
Freitag, 10. Januar 14
•
Zweistellige Vektoren
•
Hier bräuchte man eine Art polymorphen Vektor
data VectorB = Vector Bool Bool
data VectorI = Vector Int Int
data VectorC = Vector Char Char
data Vector a = Vector a a
*Main> let l = Vector 1 2
*Main> :t l
l :: Vector Integer
Algebraische Datentypen
data Vector a = Vector a a
*Main> let l = Vector 1 2
*Main> :t l
l :: Vector Integer
•
•
•
•
Freitag, 10. Januar 14
Vector auf der rechten Seite ist ein Wertkonstruktor,
Vector 1 3 konstruiert einen Wert
Vector iauf der linken Seite ist ein Typkonstruktor,
Vector Integer konstruiert einen Typ
Man kann die beiden nicht verwechseln,
Typkonstruktoren und Wertkonstruktoren kommen
nicht an den gleichen Stellen vor
Sogar data Vector a b = Vector a b geht!
Algebraische Datentypen
Beispiel: Berechnungen, die fehlschlagen können
data Maybe a = Just a | Nothing
mydiv :: Int -> Int -> Maybe Int
mydiv a b
| b == 0 = Nothing
| otherwise = Just (a `div` b)
*Main> mydiv 4 2
Just 2
*Main> mydiv 4 0
Nothing
*Main> :t mydiv 4 3
mydiv 4 3 :: Maybe Int
Freitag, 10. Januar 14
Typklassen
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Einschränkung des Typs
(aka Typeclass)
Hier kommen die Clojure Protokolle her!
Freitag, 10. Januar 14
Typklassen
• Beispiel: Eq - Dinge, die man vergleichen
kann
• Was gibt Vector
Freitag, 10. Januar 14
1 2 == Vector 1 3 ?
Typklassen
*Main> Vector 1 2 == Vector 1 3
<interactive>:137:12:
No instance for (Eq (Vector a0))
arising from a use of `=='
Possible fix: add an instance declaration for (Eq (Vector a0))
In the expression: Vector 1 2 == Vector 1 3
In an equation for `it': it = Vector 1 2 == Vector 1 3
Uns fehlt die passende type class um Vektoren zu
vergleichen
Freitag, 10. Januar 14
Eq
class Eq
(==)
(/=)
x ==
x /=
a where
:: a ->
:: a ->
y = not
y = not
a -> Bool
a -> Bool
(x /= y)
(x == y)
Default Implementierung
"extend-protocol"
instance (Eq a) => Eq (Vector a) where
(Vector x1 y1) == (Vector x2 y2) = x1==x2 && y1 == y2
Freitag, 10. Januar 14
"Eq" in Clojure
data MyVector a = MyVector a a
class Eq
(==)
(/=)
x ==
x /=
a where
:: a ->
:: a ->
y = not
y = not
a -> Bool
a -> Bool
(x /= y)
(x == y)
(defrecord MyVector [x y])
(defprotocol Eq
(eq [this that]))
instance (Eq a) => Eq (Vector a) where
(Vector x1 y1) == (Vector x2 y2) = x1==x2 && y1 == y2
(extend-protocol Eq MyVector
(eq [this that] (and (= (:x this) (:x that))
(= (:y this) (:y that)))))))
Freitag, 10. Januar 14
Seiteneffekte
• Statische Typisierung in Haskell ist anders als
in anderen statisch typisierten Sprachen
• Haskell ist pure
• In Haskell kann man am Typ erkennen, ob
eine Funktion einen Seiteneffekt hat
• Haskell ist pure und hat trotzdem
Seiteneffekte ?!?
Freitag, 10. Januar 14
Seiteneffekte
echo x = do n <- getLine
putStrLn (x ++" " ++ n)
return n
*Main> echo "Hallo"
Welt
Eingabe in der Shell
Hallo Welt
"Welt"
*Main> :t echo
echo :: [Char] -> IO String
Freitag, 10. Januar 14
Seiteneffekte
echo x = do n <- getLine
putStrLn (x ++" " ++ n)
return n
*Main> echo "Hallo"
Welt
Hallo Welt
"Welt"
*Main> :t echo
echo :: [Char] -> IO String
*Main> :t putStr
putStr :: String -> IO ()
*Main> :t getLine
getLine :: IO String
Freitag, 10. Januar 14
IO markiert
Seiteneffekte
Was ist IO String?
Freitag, 10. Januar 14
Clojure Alternativen
• Ersatz für Static typing in Clojure?
• Optional Typing mit core.typed
• Prismatic Schemas (→REPL)
• Contracts
• Tests
• Alles nur geeignet zur Fehlervermeidung,
nicht zur Erkennung von Seiteneffekten
Freitag, 10. Januar 14
Currying
Freitag, 10. Januar 14
Currying
• Benannt nach Haskell Curry
• Unabhängig auch von Moses Schönfinkel entdeckt
Freitag, 10. Januar 14
(+)
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Warum ist die Signatur nicht
(+) :: Num a => a,a -> a
Freitag, 10. Januar 14
Currying
Jede Funktion in Haskell nimmt genau
einen Parameter
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> let inc = (+) 1
Prelude> :t inc
inc :: Integer -> Integer
Eine n-stellige Funktion schreibt man als
Funktion, die einen Parameter nimmt und
eine n-1 stellige Funktion liefert
Freitag, 10. Januar 14
Currying
Haskell Typsignaturen sind also rechtsassoziativ
(+) :: Num a => a -> (a -> a)
Freitag, 10. Januar 14
Currying
Prelude> let foo x y z = (x + y) * z
Prelude> :t foo
foo :: Num a => a -> a -> a -> a
foo(1)(2)(3)
Prelude> foo 1 2 3
(((foo 1) 2) 3)
9
Prelude> let f1 = foo 1
Prelude> f2 2 3
9
Prelude> let f2 = f1 2
Prelude> f2 3
9
Prelude> let f2 = foo 1 2
Prelude> f2 3
9
Prelude> let f3 = foo 1 2 3
Prelude> f3
9
Freitag, 10. Januar 14
Partial Application
Prelude> :t take
take :: Int -> [a] -> [a]
Prelude> let take3 = take 3
Prelude> :t take3
take3 :: [a] -> [a]
Prelude> take3 [1,2,3,4,5]
[1,2,3]
Freitag, 10. Januar 14
Partial Application
Man kann das Verhalten in Clojure simulieren:
user=> (def take' (fn [n] (fn [c] (take n c))))
#'user/take'
user=> (def take3 (take' 3))
#'user/take3
user=> (take3 (range 5))
(0 1 2)
Freitag, 10. Januar 14
Partial Application
Es gibt eine weitere Möglichkeit take3 zu
schreiben
user=> (def take3 (partial take 3))
#'user/take3
user=> (take3 [1 2 3 4 5])
(1 2 3)
partial = currying?
Freitag, 10. Januar 14
Currying
• Allgemeines Currying ist in Clojure nicht
direkt realisierbar
• Grund: variable Anzahl an Argumenten
• Was ist das Resultat von (+ 2 3)?
• 5?
• Eine Funktion, die +5 rechnet?
Currying geht nur wenn wir die Anzahl der
Parameter fixieren
Freitag, 10. Januar 14
Curry Macro
(defmacro curry
([n f] `(curry ~n [] ~f))
([n p f]
(if (= 0 n) `(~f ~@p)
(let [x (gensym)]
`(fn [~x] (curry ~(dec n) ~(conj p x) ~f))))))
user=> (def +c2 (curry 2 +))
#'user/+c2
user=> (+c2 1)
#<PLUS_c2$fn... PLUS_c2$fn...>
user=> ((+c2 1) 4)
5
user=> (macroexpand-all '(curry 2 +))
(fn* ([G__3943] (fn* ([G__3944] (+ G__3943 G__3944)))))
Freitag, 10. Januar 14
Herunterladen