< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
Print this page
private final TransTypes transTypes;
private final boolean debugLower;
private final boolean disableProtectedAccessors; // experimental
private final PkgInfo pkginfoOpt;
private final boolean optimizeOuterThis;
+ private final boolean allowPrimitiveClasses;
private final boolean useMatchException;
@SuppressWarnings("this-escape")
protected Lower(Context context) {
context.put(lowerKey, this);
optimizeOuterThis =
target.optimizeOuterThis() ||
options.getBoolean("optimizeOuterThis", false);
disableProtectedAccessors = options.isSet("disableProtectedAccessors");
Source source = Source.instance(context);
+ allowPrimitiveClasses = Source.Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
Preview preview = Preview.instance(context);
useMatchException = Feature.PATTERN_SWITCH.allowedInSource(source) &&
(preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH));
}
for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
ClassSymbol c = l.head;
if (isTranslatedClassAvailable(c))
continue;
// Create class definition tree.
- JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
+ JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE,
c.outermostClass(), c.flatname, false);
swapAccessConstructorTag(c, cdec.sym);
translated.append(cdec);
}
}
if (target.hasNestmateAccess()) {
return false;
}
if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
return false;
- } else if (sym.name == names.init && sym.owner.isDirectlyOrIndirectlyLocal()) {
+ } else if (names.isInitOrVNew(sym.name) && sym.owner.isDirectlyOrIndirectlyLocal()) {
// private constructor in local class: relax protection
sym.flags_field &= ~PRIVATE;
return false;
} else {
return true;
}
JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null;
switch (sym.kind) {
case TYP:
if (sym.owner.kind != PCK) {
+ // Make sure not to lose type fidelity due to symbol sharing between projections
+ boolean requireReferenceProjection = allowPrimitiveClasses &&
+ tree.hasTag(SELECT) && ((JCFieldAccess) tree).name == names.ref && tree.type.isReferenceProjection();
// Convert type idents to
// <flat name> or <package name> . <flat name>
Name flatname = Convert.shortName(sym.flatName());
while (base != null &&
TreeInfo.symbol(base) != null &&
if (tree.hasTag(IDENT)) {
((JCIdent) tree).name = flatname;
} else if (base == null) {
tree = make.at(tree.pos).Ident(sym);
((JCIdent) tree).name = flatname;
+ if (requireReferenceProjection) {
+ tree.setType(tree.type.referenceProjection());
+ }
} else {
((JCFieldAccess) tree).selected = base;
((JCFieldAccess) tree).name = flatname;
+ if (requireReferenceProjection) {
+ tree.setType(tree.type.referenceProjection());
+ }
}
}
break;
case MTH: case VAR:
if (sym.owner.kind == TYP) {
List<Type> argtypes = constr.type.getParameterTypes();
if ((accOwner.flags_field & ENUM) != 0)
argtypes = argtypes
.prepend(syms.intType)
.prepend(syms.stringType);
+ Name constructorName = accOwner.isConcreteValueClass() ? names.vnew : names.init;
aconstr = new MethodSymbol(
SYNTHETIC,
- names.init,
+ constructorName,
new MethodType(
argtypes.append(
accessConstructorTag().erasure(types)),
constr.type.getReturnType(),
constr.type.getThrownTypes(),
Name flatname = names.fromString("" + topClass.getQualifiedName() +
target.syntheticNameChar() +
i);
ClassSymbol ctag = chk.getCompiled(topModle, flatname);
if (ctag == null)
- ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
+ ctag = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, topClass).sym;
else if (!ctag.isAnonymous())
continue;
// keep a record of all tags, to verify that all are generated as required
accessConstrTags = accessConstrTags.prepend(ctag);
return ctag;
* @param sym The symbol.
*/
void makeAccessible(Symbol sym) {
JCClassDecl cdef = classDef(sym.owner.enclClass());
if (cdef == null) Assert.error("class def not found: " + sym + " in " + sym.owner);
- if (sym.name == names.init) {
+ if (names.isInitOrVNew(sym.name)) {
cdef.defs = cdef.defs.prepend(
accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
} else {
MethodSymbol[] accessors = accessSyms.get(sym);
for (int i = 0; i < AccessCode.numberOfAccessCodes; i++) {
*/
JCVariableDecl outerThisDef(int pos, MethodSymbol owner) {
ClassSymbol c = owner.enclClass();
boolean isMandated =
// Anonymous constructors
- (owner.isConstructor() && owner.isAnonymous()) ||
+ (owner.isInitOrVNew() && owner.isAnonymous()) ||
// Constructors of non-private inner member classes
- (owner.isConstructor() && c.isInner() &&
+ (owner.isInitOrVNew() && c.isInner() &&
!c.isPrivate() && !c.isStatic());
long flags =
FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
owner.extraParams = owner.extraParams.prepend(outerThis);
return newBlock;
}
private JCStatement makeResourceCloseInvocation(JCExpression resource) {
// convert to AutoCloseable if needed
- if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
+ if (types.asSuper(resource.type.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) == null) {
resource = convert(resource, syms.autoCloseableType);
}
// create resource.close() method invocation
JCExpression resourceClose = makeCall(resource,
Scope s = clazz.members();
for (Symbol sym : s.getSymbols(NON_RECURSIVE))
if (sym.kind == TYP &&
sym.name == names.empty &&
(sym.flags() & INTERFACE) == 0) return (ClassSymbol) sym;
- return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
+ return makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, clazz).sym;
}
/** Create an attributed tree of the form left.name(). */
private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
Assert.checkNonNull(left.type);
/**Used to create an auxiliary class to hold $assertionsDisabled for interfaces.
*/
private ClassSymbol assertionsDisabledClass() {
if (assertionsDisabledClassCache != null) return assertionsDisabledClassCache;
- assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC, outermostClassDef.sym).sym;
+ assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, outermostClassDef.sym).sym;
return assertionsDisabledClassCache;
}
// This code is not particularly robust if the user has
}
/** Visitor method: Translate a single node, boxing or unboxing if needed.
*/
public <T extends JCExpression> T translate(T tree, Type type) {
- return (tree == null) ? null : boxIfNeeded(translate(tree), type);
+ return (tree == null) ? null :
+ applyPrimitiveConversionsAsNeeded(boxIfNeeded(translate(tree), type), type);
}
/** Visitor method: Translate tree.
*/
public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
seen = unseen;
}
// Convert a protected modifier to public, mask static modifier.
if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
- tree.mods.flags &= ClassFlags;
+ tree.mods.flags &= AdjustedClassFlags;
// Convert name to flat representation, replacing '.' by '$'.
tree.name = Convert.shortName(currentClass.flatName());
// Add free variables proxy definitions to class.
qualifier.type = msym.type.asMethodType().restype;
return qualifier;
}
public void visitMethodDef(JCMethodDecl tree) {
+ // TODO - enum so is always <init>
if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
// Add "String $enum$name, int $enum$ordinal" to the beginning of the
// argument list for each constructor of an enum.
JCVariableDecl nameParam = make_at(tree.pos()).
Param(names.fromString(target.syntheticNameChar() +
currentMethodSym = prevMethodSym;
}
}
private void visitMethodDefInternal(JCMethodDecl tree) {
- if (tree.name == names.init &&
+ if (names.isInitOrVNew(tree.name) &&
!currentClass.isStatic() &&
(currentClass.isInner() || currentClass.isDirectlyOrIndirectlyLocal())) {
// We are seeing a constructor of an inner class.
MethodSymbol m = tree.sym;
super.visitMethodDef(tree);
} finally {
lambdaTranslationMap = prevLambdaTranslationMap;
}
}
- if (tree.name == names.init && ((tree.sym.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
+ if (names.isInitOrVNew(tree.name) && ((tree.sym.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
(tree.sym.flags_field & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD))) {
// lets find out if there is any field waiting to be initialized
ListBuffer<VarSymbol> fields = new ListBuffer<>();
for (Symbol sym : currentClass.getEnclosedElements()) {
if (sym.kind == Kinds.Kind.VAR && ((sym.flags() & RECORD) != 0))
}
public void visitApply(JCMethodInvocation tree) {
Symbol meth = TreeInfo.symbol(tree.meth);
List<Type> argtypes = meth.type.getParameterTypes();
- if (meth.name == names.init && meth.owner == syms.enumSym)
+ // TODO - is enum so always <init>.
+ if (names.isInitOrVNew(meth.name) && meth.owner == syms.enumSym)
argtypes = argtypes.tail.tail;
tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
tree.varargsElement = null;
Name methName = TreeInfo.name(tree.meth);
- if (meth.name==names.init) {
+ if (names.isInitOrVNew(meth.name)) {
// We are seeing a this(...) or super(...) constructor call.
// If an access constructor is used, append null as a last argument.
Symbol constructor = accessConstructor(tree.pos(), meth);
if (constructor != meth) {
tree.args = tree.args.append(makeNull());
if (!anyChanges) return _args;
}
return result.toList();
}
+ /** Apply primitive value/reference conversions as needed */
+ @SuppressWarnings("unchecked")
+ <T extends JCExpression> T applyPrimitiveConversionsAsNeeded(T tree, Type type) {
+ boolean haveValue = tree.type.isPrimitiveClass();
+ if (haveValue == type.isPrimitiveClass())
+ return tree;
+ // For narrowing conversion, insert a cast which should trigger a null check
+ // For widening conversions, insert a cast if emitting a unified class file.
+ return (T) make.TypeCast(type, tree);
+ }
+
/** Expand a boxing or unboxing conversion if needed. */
@SuppressWarnings("unchecked") // XXX unchecked
<T extends JCExpression> T boxIfNeeded(T tree, Type type) {
boolean havePrimitive = tree.type.isPrimitive();
if (havePrimitive == type.isPrimitive())
* where #i is a freshly named synthetic local variable.
*/
private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
make_at(tree.expr.pos());
Type iteratorTarget = syms.objectType;
- Type iterableType = types.asSuper(types.cvarUpperBound(tree.expr.type),
+ Type iterableType = types.asSuper(types.cvarUpperBound(tree.expr.type.referenceProjectionOrSelf()),
syms.iterableType.tsym);
if (iterableType.getTypeArguments().nonEmpty())
iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
tree.expr.type = types.erasure(types.skipTypeVars(tree.expr.type, false));
tree.expr = transTypes.coerce(attrEnv, tree.expr, types.erasure(iterableType));
Symbol iterator = lookupMethod(tree.expr.pos(),
names.iterator,
tree.expr.type,
List.nil());
- Assert.check(types.isSameType(types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)), types.erasure(syms.iteratorType)));
+ Assert.check(types.isSameType(types.erasure(types.asSuper(iterator.type.getReturnType().referenceProjectionOrSelf(), syms.iteratorType.tsym)), types.erasure(syms.iteratorType)));
VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
types.erasure(syms.iteratorType),
currentMethodSym);
JCStatement init = make.
tree.cond = translate(tree.cond, syms.booleanType);
tree.body = translate(tree.body);
result = tree;
}
+ public void visitWithField(JCWithField tree) {
+ Type fieldType = tree.field.type;
+ tree.field = translate(tree.field, tree);
+ tree.value = translate(tree.value, fieldType); // important to use pre-translation type.
+
+ // If translated field is an Apply, we are
+ // seeing an access method invocation. In this case, append
+ // right hand side as last argument of the access method.
+ if (tree.field.hasTag(APPLY)) {
+ JCMethodInvocation app = (JCMethodInvocation) tree.field;
+ app.args = List.of(tree.value).prependList(app.args);
+ result = app;
+ } else {
+ result = tree;
+ }
+ }
+
public void visitForLoop(JCForLoop tree) {
tree.init = translate(tree.init);
if (tree.cond != null)
tree.cond = translate(tree.cond, syms.booleanType);
tree.step = translate(tree.step);
// is a default interface subclassed by the current class.
boolean qualifiedSuperAccess =
tree.selected.hasTag(SELECT) &&
TreeInfo.name(tree.selected) == names._super &&
!types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
+ /* JDK-8269956: Where a reflective (class) literal is needed, the unqualified Point.class is
+ * always the "primary" mirror - representing the primitive reference runtime type - thereby
+ * always matching the behavior of Object::getClass
+ */
+ boolean needPrimaryMirror = tree.name == names._class && tree.selected.type.isReferenceProjection();
tree.selected = translate(tree.selected);
+ if (needPrimaryMirror && allowPrimitiveClasses && tree.selected.type.isPrimitiveClass()) {
+ tree.selected.setType(tree.selected.type.referenceProjection());
+ }
if (tree.name == names._class) {
result = classOf(tree.selected);
}
else if (tree.name == names._super &&
types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
//default super call!! Not a classic qualified super call
TypeSymbol supSym = tree.selected.type.tsym;
- Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
+ Assert.checkNonNull(types.asSuper(currentClass.type.referenceProjectionOrSelf(), supSym));
result = tree;
}
else if (tree.name == names._this || tree.name == names._super) {
result = makeThis(tree.pos(), tree.selected.type.tsym);
}
< prev index next >