8159970: javac, JLS8 18.2.4 is not completely implemented by the compiler

Reviewed-by: mcimadamore
This commit is contained in:
Vicente Romero 2016-06-28 15:29:20 -07:00
parent 11272cf548
commit 0df5aa8678
9 changed files with 338 additions and 23 deletions

View File

@ -1126,10 +1126,13 @@ public class Types {
@Override
public Boolean visitWildcardType(WildcardType t, Type s) {
if (s.isPartial())
return visit(s, t);
else
if (!s.hasTag(WILDCARD)) {
return false;
} else {
WildcardType t2 = (WildcardType)s;
return (t.kind == t2.kind || (t.isExtendsBound() && s.isExtendsBound())) &&
isSameType(t.type, t2.type, true);
}
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2016, 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
@ -67,7 +67,7 @@ import com.sun.tools.javac.util.Warner;
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
class InferenceContext {
public class InferenceContext {
/** list of inference vars as undet vars */
List<Type> undetvars;
@ -111,6 +111,13 @@ class InferenceContext {
return inferencevars;
}
/**
* returns the list of undetermined variables in this inference context
*/
public List<Type> undetVars() {
return undetvars;
}
/**
* returns the list of uninstantiated variables (as type-variables) in this
* inference context
@ -208,7 +215,7 @@ class InferenceContext {
* undet vars (used ahead of subtyping/compatibility checks to allow propagation
* of inference constraints).
*/
final Type asUndetVar(Type t) {
public final Type asUndetVar(Type t) {
return types.subst(t, inferencevars, undetvars);
}
@ -286,7 +293,7 @@ class InferenceContext {
/**
* Save the state of this inference context
*/
List<Type> save() {
public List<Type> save() {
ListBuffer<Type> buf = new ListBuffer<>();
for (Type t : undetvars) {
buf.add(((UndetVar)t).dup(infer.types));
@ -298,7 +305,7 @@ class InferenceContext {
* Consider that the number of saved undetermined variables can be different to the current
* amount. This is because new captured variables could have been added.
*/
void rollback(List<Type> saved_undet) {
public void rollback(List<Type> saved_undet) {
Assert.check(saved_undet != null);
//restore bounds (note: we need to preserve the old instances)
ListBuffer<Type> newUndetVars = new ListBuffer<>();

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2016, 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 8159970
* @summary javac, JLS8 18.2.4 is not completely implemented by the compiler
* @library /tools/lib/types
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.comp
* jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
* jdk.compiler/com.sun.tools.javac.file
* @build TypeHarness
* @run main TypeEqualityInInferenceTest
*/
import java.util.ArrayList;
import java.util.List;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.UndetVar;
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
import com.sun.tools.javac.util.Assert;
public class TypeEqualityInInferenceTest extends TypeHarness {
StrToTypeFactory strToTypeFactory;
public static void main(String... args) throws Exception {
new TypeEqualityInInferenceTest().runAll();
}
void runAll() {
List<String> imports = new ArrayList<>();
imports.add("java.util.*");
List<String> typeVars = new ArrayList<>();
typeVars.add("T");
strToTypeFactory = new StrToTypeFactory(null, imports, typeVars);
runTest("List<? extends T>", "List<? extends String>", predef.stringType);
runTest("List<? extends T>", "List<?>", predef.objectType);
runTest("List<? super T>", "List<? super String>", predef.stringType);
}
void runTest(String freeTypeStr, String typeStr, Type equalityBoundType) {
Type freeType = strToTypeFactory.getType(freeTypeStr);
Type aType = strToTypeFactory.getType(typeStr);
withInferenceContext(strToTypeFactory.getTypeVars(), inferenceContext -> {
assertSameType(inferenceContext.asUndetVar(freeType), aType);
UndetVar undetVarForT = (UndetVar)inferenceContext.undetVars().head;
checkEqualityBound(undetVarForT, equalityBoundType);
});
withInferenceContext(strToTypeFactory.getTypeVars(), inferenceContext -> {
assertSameType(aType, inferenceContext.asUndetVar(freeType));
UndetVar undetVarForT = (UndetVar)inferenceContext.undetVars().head;
checkEqualityBound(undetVarForT, equalityBoundType);
});
}
void checkEqualityBound(UndetVar uv, Type boundType) {
com.sun.tools.javac.util.List<Type> equalBounds = uv.getBounds(InferenceBound.EQ);
Assert.check(!equalBounds.isEmpty() && equalBounds.length() == 1,
"undetVar must have only one equality bound");
Type bound = equalBounds.head;
Assert.check(bound == boundType, "equal bound must be of type " + boundType);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2016, 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
@ -26,17 +26,18 @@
* @bug 7006109
* @summary Add test library to simplify the task of writing automated type-system tests
* @author mcimadamore
* @library .
* @library /tools/lib/types
* @modules jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.comp
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.util
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.tree
* @build TypeHarness
* @run main BoxingConversionTest
*/
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Symbol.*;
import java.lang.reflect.Array;
import java.util.EnumSet;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2016, 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
@ -26,11 +26,14 @@
* @bug 7006109
* @summary Add test library to simplify the task of writing automated type-system tests
* @author mcimadamore
* @library .
* @library /tools/lib/types
* @modules jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.comp
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.util
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.tree
* @build TypeHarness
* @run main CastTest
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2016, 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
@ -26,11 +26,14 @@
* @bug 7007432 7006109
* @summary Test generic types well-formedness
* @author mcimadamore
* @library .
* @library /tools/lib/types
* @modules jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.comp
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.util
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.tree
* @build TypeHarness
* @run main GenericTypeWellFormednessTest
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2016, 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
@ -26,17 +26,19 @@
* @bug 7006109
* @summary Add test library to simplify the task of writing automated type-system tests
* @author mcimadamore
* @library .
* @library /tools/lib/types
* @modules jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.comp
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.util
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.tree
* @build TypeHarness
* @run main PrimitiveConversionTest
*/
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Symbol.*;
import java.lang.reflect.Array;
import java.util.EnumSet;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016, 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
@ -29,8 +29,6 @@
*/
import java.io.*;
import java.lang.reflect.Array;
import java.util.EnumSet;
public class TestComparisons {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2016, 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
@ -21,6 +21,13 @@
* questions.
*/
import java.net.URI;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.util.Context;
@ -29,12 +36,22 @@ import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.comp.Attr;
import com.sun.tools.javac.comp.Check;
import com.sun.tools.javac.comp.Infer;
import com.sun.tools.javac.comp.InferenceContext;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.Abort;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import static com.sun.tools.javac.util.List.*;
/**
* Test harness whose goal is to simplify the task of writing type-system
@ -72,12 +89,18 @@ public class TypeHarness {
protected Check chk;
protected Symtab predef;
protected Names names;
protected ReusableJavaCompiler tool;
protected Infer infer;
protected Factory fac;
protected TypeHarness() {
Context ctx = new Context();
JavacFileManager.preRegister(ctx);
MyAttr.preRegister(ctx);
tool = new ReusableJavaCompiler(ctx);
types = Types.instance(ctx);
infer = Infer.instance(ctx);
chk = Check.instance(ctx);
predef = Symtab.instance(ctx);
names = Names.instance(ctx);
@ -177,6 +200,23 @@ public class TypeHarness {
}
// </editor-fold>
/** Creates an inference context given a list of type variables and performs the given action on it.
* The intention is to provide a way to do unit testing on inference contexts.
* @param typeVars a list of type variables to create the inference context from
* @param consumer the action to be performed on the inference context
*/
protected void withInferenceContext(List<Type> typeVars, Consumer<InferenceContext> consumer) {
Assert.check(!typeVars.isEmpty(), "invalid parameter, empty type variables list");
ListBuffer undetVarsBuffer = new ListBuffer();
typeVars.stream().map((tv) -> new UndetVar((TypeVar)tv, null, types)).forEach((undetVar) -> {
undetVarsBuffer.add(undetVar);
});
List<Type> undetVarsList = undetVarsBuffer.toList();
InferenceContext inferenceContext = new InferenceContext(infer, nil(), undetVarsList);
inferenceContext.rollback(undetVarsList);
consumer.accept(inferenceContext);
}
private void error(String msg) {
throw new AssertionError("Unexpected result: " + msg);
}
@ -330,4 +370,171 @@ public class TypeHarness {
}
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="StrToTypeFactory">
/**
* StrToTypeFactory is a class provided to ease the creation of complex types from Strings.
* The client code can specify a package, a list of imports and a list of type variables when
* creating an instance of StrToTypeFactory. Later types including, or not, these type variables
* can be created by the factory. All occurrences of the same type variable in a type defined
* using a String are guaranteed to refer to the same type variable in the created type.
*
* An example is reported below:
*
* <pre>
* List<String> imports = new ArrayList<>();
* imports.add("java.util.*");
* List<String> typeVars = new ArrayList<>();
* typeVars.add("T");
* strToTypeFactory = new StrToTypeFactory(null, imports, typeVars);
*
* Type freeType = strToTypeFactory.getType("List<? extends T>");
* Type aType = strToTypeFactory.getType("List<? extends String>");
*
* // method withInferenceContext() belongs to TypeHarness
* withInferenceContext(strToTypeFactory.getTypeVars(), inferenceContext -> {
* assertSameType(inferenceContext.asUndetVar(freeType), aType);
* UndetVar undetVarForT = (UndetVar)inferenceContext.undetVars().head;
* com.sun.tools.javac.util.List<Type> equalBounds = undetVarForT.getBounds(InferenceBound.EQ);
* Assert.check(!equalBounds.isEmpty() && equalBounds.length() == 1,
* "undetVar must have only one equality bound");
* });
* </pre>
*/
public class StrToTypeFactory {
int id = 0;
String pkg;
java.util.List<String> imports;
public java.util.List<String> typeVarDecls;
public List<Type> typeVariables;
public StrToTypeFactory(String pkg, java.util.List<String> imports, java.util.List<String> typeVarDecls) {
this.pkg = pkg;
this.imports = imports;
this.typeVarDecls = typeVarDecls;
this.typeVariables = from(typeVarDecls.stream()
.map(this::typeVarName)
.map(this::getType)
.collect(Collectors.toList())
);
}
TypeVar getTypeVarFromStr(String name) {
if (typeVarDecls == null) {
return null;
}
int index = typeVarDecls.indexOf(name);
if (index != -1) {
return (TypeVar)typeVariables.get(index);
}
return null;
}
List<Type> getTypeVars() {
return typeVariables;
}
String typeVarName(String typeVarDecl) {
String[] ss = typeVarDecl.split(" ");
return ss[0];
}
public final Type getType(String type) {
JavaSource source = new JavaSource(type);
MyAttr.theType = null;
MyAttr.typeParameters = List.nil();
tool.clear();
List<JavaFileObject> inputs = of(source);
try {
tool.compile(inputs);
} catch (Throwable ex) {
throw new Abort(ex);
}
if (typeVariables != null) {
return types.subst(MyAttr.theType, MyAttr.typeParameters, typeVariables);
}
return MyAttr.theType;
}
class JavaSource extends SimpleJavaFileObject {
String id;
String type;
String template = "#Package;\n" +
"#Imports\n" +
"class G#Id#TypeVars {\n" +
" #FieldType var;" +
"}";
JavaSource(String type) {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
this.id = String.valueOf(StrToTypeFactory.this.id++);
this.type = type;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
String impStmts = imports.size() > 0 ?
imports.stream().map(i -> "import " + i + ";").collect(Collectors.joining("\n")) : "";
String tvars = typeVarDecls.size() > 0 ?
typeVarDecls.stream().collect(Collectors.joining(",", "<", ">")) : "";
return template
.replace("#Package", (pkg == null) ? "" : "package " + pkg + ";")
.replace("#Imports", impStmts)
.replace("#Id", id)
.replace("#TypeVars", tvars)
.replace("#FieldType", type);
}
}
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="helper classes">
static class MyAttr extends Attr {
private static Type theType;
private static List<Type> typeParameters = List.nil();
static void preRegister(Context context) {
context.put(attrKey, (com.sun.tools.javac.util.Context.Factory<Attr>) c -> new MyAttr(c));
}
MyAttr(Context context) {
super(context);
}
@Override
public void visitVarDef(JCVariableDecl tree) {
super.visitVarDef(tree);
theType = tree.type;
}
@Override
public void attribClass(DiagnosticPosition pos, ClassSymbol c) {
super.attribClass(pos, c);
ClassType ct = (ClassType)c.type;
typeParameters = ct.typarams_field;
}
}
static class ReusableJavaCompiler extends JavaCompiler {
ReusableJavaCompiler(Context context) {
super(context);
}
@Override
protected void checkReusable() {
// do nothing
}
@Override
public void close() {
//do nothing
}
void clear() {
newRound();
}
}
// </editor-fold>
}