From 4635531950dbcfcd3ee2f13a57f0909af78a94c7 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 15 Jul 2024 14:24:27 +0000 Subject: [PATCH] 8335159: Move method reference to lambda desugaring before Lower 8336320: NullPointerException: Cannot invoke Type.getTag because type is null after JDK-8334037 Reviewed-by: jlahoda, vromero --- .../com/sun/tools/javac/comp/Lower.java | 335 ------------------ .../com/sun/tools/javac/comp/TransTypes.java | 287 ++++++++++++++- .../javac/SuperInit/MrefDoubleTrans.java | 38 ++ 3 files changed, 307 insertions(+), 353 deletions(-) create mode 100644 test/langtools/tools/javac/SuperInit/MrefDoubleTrans.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index 7ab38e86366..6a5d75d7a89 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -29,7 +29,6 @@ import java.util.*; import java.util.stream.Collectors; import com.sun.source.tree.LambdaExpressionTree.BodyKind; -import com.sun.source.tree.MemberReferenceTree.ReferenceMode; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Kinds.KindSelector; import com.sun.tools.javac.code.Scope.WriteableScope; @@ -39,7 +38,6 @@ import com.sun.tools.javac.main.Option.PkgInfo; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.resources.CompilerProperties.Notes; import com.sun.tools.javac.tree.*; -import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; @@ -67,8 +65,6 @@ import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT; import com.sun.tools.javac.tree.JCTree.JCSwitchExpression; -import javax.lang.model.type.TypeKind; - import static com.sun.tools.javac.tree.JCTree.Tag.*; /** This pass translates away some syntactic sugar: inner classes, @@ -3903,337 +3899,6 @@ public class Lower extends TreeTranslator { result = tree; } - @Override - public void visitReference(JCMemberReference tree) { - if (needsConversionToLambda(tree)) { - // Convert to a lambda, and process as such - MemberReferenceToLambda conv = new MemberReferenceToLambda(tree); - result = translate(conv.lambda()); - } else { - super.visitReference(tree); - } - } - // where - boolean needsVarArgsConversion(JCMemberReference tree) { - return tree.varargsElement != null; - } - - /** - * @return Is this an array operation like clone() - */ - boolean isArrayOp(JCMemberReference tree) { - return tree.sym.owner == syms.arrayClass; - } - - boolean receiverAccessible(JCMemberReference tree) { - //hack needed to workaround 292 bug (7087658) - //when 292 issue is fixed we should remove this and change the backend - //code to always generate a method handle to an accessible method - return tree.ownerAccessible; - } - - /** - * Erasure destroys the implementation parameter subtype - * relationship for intersection types. - * Have similar problems for union types too. - */ - boolean interfaceParameterIsIntersectionOrUnionType(JCMemberReference tree) { - List tl = tree.getDescriptorType(types).getParameterTypes(); - for (; tl.nonEmpty(); tl = tl.tail) { - Type pt = tl.head; - if (isIntersectionOrUnionType(pt)) - return true; - } - return false; - } - - boolean isIntersectionOrUnionType(Type t) { - switch (t.getKind()) { - case INTERSECTION: - case UNION: - return true; - case TYPEVAR: - TypeVar tv = (TypeVar) t; - return isIntersectionOrUnionType(tv.getUpperBound()); - } - return false; - } - - private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference, - Symbol currentClass) { - return ((targetReference.flags() & PROTECTED) != 0 && - targetReference.packge() != currentClass.packge()); - } - - /** - * This method should be called only when target release <= 14 - * where LambdaMetaFactory does not spin nestmate classes. - * - * This method should be removed when --release 14 is not supported. - */ - boolean isPrivateInOtherClass(JCMemberReference tree) { - assert !target.runtimeUseNestAccess(); - return (tree.sym.flags() & PRIVATE) != 0 && - !types.isSameType( - types.erasure(tree.sym.enclClass().asType()), - types.erasure(currentClass.asType())); - } - - /** - * Does this reference need to be converted to a lambda - * (i.e. var args need to be expanded or "super" is used) - */ - boolean needsConversionToLambda(JCMemberReference tree) { - return interfaceParameterIsIntersectionOrUnionType(tree) || - tree.hasKind(ReferenceKind.SUPER) || - needsVarArgsConversion(tree) || - isArrayOp(tree) || - (!target.runtimeUseNestAccess() && isPrivateInOtherClass(tree)) || - isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, currentClass) || - !receiverAccessible(tree) || - (tree.getMode() == ReferenceMode.NEW && - tree.kind != ReferenceKind.ARRAY_CTOR && - (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner())); - } - - /** - * Converts a method reference which cannot be used directly into a lambda - */ - private class MemberReferenceToLambda { - - private final JCMemberReference tree; - private final ListBuffer args = new ListBuffer<>(); - private final ListBuffer params = new ListBuffer<>(); - private final MethodSymbol owner = new MethodSymbol(0, names.empty, Type.noType, currentClass); - - private JCExpression receiverExpression = null; - - MemberReferenceToLambda(JCMemberReference tree) { - this.tree = tree; - } - - JCExpression lambda() { - int prevPos = make.pos; - try { - make.at(tree); - - //body generation - this can be either a method call or a - //new instance creation expression, depending on the member reference kind - VarSymbol rcvr = addParametersReturnReceiver(); - JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) - ? expressionInvoke(rcvr) - : expressionNew(); - - JCLambda slam = make.Lambda(params.toList(), expr); - slam.target = tree.target; - slam.type = tree.type; - slam.pos = tree.pos; - slam.wasMethodReference = true; - if (receiverExpression != null) { - // use a let expression so that the receiver expression is evaluated eagerly - return make.at(tree.pos).LetExpr( - make.VarDef(rcvr, translate(receiverExpression)), slam).setType(tree.type); - } else { - return slam; - } - } finally { - make.at(prevPos); - } - } - - /** - * Generate the parameter list for the converted member reference. - * - * @return The receiver variable symbol, if any - */ - VarSymbol addParametersReturnReceiver() { - Type samDesc = types.erasure(types.findDescriptorSymbol(tree.target.tsym).type); - List samPTypes = samDesc.getParameterTypes(); - List descPTypes = tree.getDescriptorType(types).getParameterTypes(); - - // Determine the receiver, if any - VarSymbol rcvr; - switch (tree.kind) { - case BOUND: - // The receiver is explicit in the method reference - rcvr = new VarSymbol(SYNTHETIC, names.fromString("rec$"), tree.getQualifierExpression().type, owner); - rcvr.pos = tree.pos; - receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); - break; - case UNBOUND: - // The receiver is the first parameter, extract it and - // adjust the SAM and unerased type lists accordingly - rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); - samPTypes = samPTypes.tail; - descPTypes = descPTypes.tail; - break; - default: - rcvr = null; - break; - } - List implPTypes = tree.sym.type.getParameterTypes(); - int implSize = implPTypes.size(); - int samSize = samPTypes.size(); - // Last parameter to copy from referenced method, exclude final var args - int last = needsVarArgsConversion(tree) ? implSize - 1 : implSize; - - // Failsafe -- assure match-up - boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); - - // Use parameter types of the implementation method unless the unerased - // SAM parameter type is an intersection type, in that case use the - // erased SAM parameter type so that the supertype relationship - // the implementation method parameters is not obscured. - // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes - // are used as pointers to the current parameter type information - // and are thus not usable afterwards. - for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { - // By default use the implementation method parameter type - Type parmType = implPTypes.head; - if (checkForIntersection) { - if (descPTypes.head.getKind() == TypeKind.INTERSECTION) { - parmType = samPTypes.head; - } - // If the unerased parameter type is a type variable whose - // bound is an intersection (eg. ) then - // use the SAM parameter type - if (descPTypes.head.getKind() == TypeKind.TYPEVAR) { - TypeVar tv = (TypeVar) descPTypes.head; - if (tv.getUpperBound().getKind() == TypeKind.INTERSECTION) { - parmType = samPTypes.head; - } - } - } - addParameter("x$" + i, parmType, true); - - // Advance to the next parameter - implPTypes = implPTypes.tail; - samPTypes = samPTypes.tail; - descPTypes = descPTypes.tail; - } - // Flatten out the var args - for (int i = last; i < samSize; ++i) { - addParameter("xva$" + i, tree.varargsElement, true); - } - - return rcvr; - } - - private JCExpression makeReceiver(VarSymbol rcvr) { - if (rcvr == null) return null; - JCExpression rcvrExpr = make.Ident(rcvr); - boolean protAccess = - isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, currentClass); - Type rcvrType = tree.ownerAccessible && !protAccess ? tree.sym.enclClass().type - : tree.expr.type; - if (rcvrType == syms.arrayClass.type) { - // Map the receiver type to the actually type, not just "array" - rcvrType = tree.getQualifierExpression().type; - } - if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { - rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); - } - return rcvrExpr; - } - - /** - * determine the receiver of the method call - the receiver can - * be a type qualifier, the synthetic receiver parameter or 'super'. - */ - private JCExpression expressionInvoke(VarSymbol rcvr) { - JCExpression qualifier = - (rcvr != null) ? - makeReceiver(rcvr) : - tree.getQualifierExpression(); - - //create the qualifier expression - JCFieldAccess select = make.Select(qualifier, tree.sym.name); - select.sym = tree.sym; - select.type = tree.sym.erasure(types); - - //create the method call expression - JCExpression apply = make.Apply(List.nil(), select, - convertArgs(tree.sym, args.toList(), tree.varargsElement)). - setType(tree.sym.erasure(types).getReturnType()); - - apply = transTypes.coerce(attrEnv, apply, - types.erasure(tree.referentType.getReturnType())); - - setVarargsIfNeeded(apply, tree.varargsElement); - return apply; - } - - /** - * Lambda body to use for a 'new'. - */ - private JCExpression expressionNew() { - if (tree.kind == ReferenceKind.ARRAY_CTOR) { - //create the array creation expression - JCNewArray newArr = make.NewArray( - make.Type(types.elemtype(tree.getQualifierExpression().type)), - List.of(make.Ident(params.first())), - null); - newArr.type = tree.getQualifierExpression().type; - return newArr; - } else { - //create the instance creation expression - //note that method reference syntax does not allow an explicit - //enclosing class (so the enclosing class is null) - // but this may need to be patched up later with the proxy for the outer this - JCNewClass newClass = make.NewClass(null, - List.nil(), - make.Type(tree.getQualifierExpression().type), - convertArgs(tree.sym, args.toList(), tree.varargsElement), - null); - newClass.constructor = tree.sym; - newClass.constructorType = tree.sym.erasure(types); - newClass.type = tree.getQualifierExpression().type; - setVarargsIfNeeded(newClass, tree.varargsElement); - return newClass; - } - } - - private VarSymbol addParameter(String name, Type p, boolean genArg) { - VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); - vsym.pos = tree.pos; - params.append(make.VarDef(vsym, null)); - if (genArg) { - args.append(make.Ident(vsym)); - } - return vsym; - } - } - - /** - * Convert method/constructor arguments by inserting appropriate cast - * as required by type-erasure - this is needed when bridging a lambda/method - * reference, as the bridged signature might require downcast to be compatible - * with the generated signature. - */ - private List convertArgs(Symbol meth, List args, Type varargsElement) { - Assert.check(meth.kind == MTH); - List formals = types.erasure(meth.type).getParameterTypes(); - if (varargsElement != null) { - Assert.check((meth.flags() & VARARGS) != 0); - } - return transTypes.translateArgs(args, formals, varargsElement, attrEnv); - } - - /** - * Set varargsElement field on a given tree (must be either a new class tree - * or a method call tree) - */ - private void setVarargsIfNeeded(JCTree tree, Type varargsElement) { - if (varargsElement != null) { - switch (tree.getTag()) { - case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break; - case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break; - case TYPECAST: setVarargsIfNeeded(((JCTypeCast) tree).expr, varargsElement); break; - default: throw new AssertionError(); - } - } - } - public void visitSwitch(JCSwitch tree) { List cases = tree.patternSwitch ? addDefaultIfNeeded(tree.patternSwitch, tree.wasEnumSelector, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java index d1ea1651041..bfe35dbec9c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -26,10 +26,13 @@ package com.sun.tools.javac.comp; +import com.sun.source.tree.MemberReferenceTree.ReferenceMode; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Attribute.TypeCompound; import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.Type.TypeVar; +import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; @@ -46,6 +49,8 @@ import static com.sun.tools.javac.code.TypeTag.VOID; import static com.sun.tools.javac.comp.CompileStates.CompileState; import com.sun.tools.javac.tree.JCTree.JCBreak; +import javax.lang.model.type.TypeKind; + /** This pass translates Generic Java to conventional Java. * *

This is NOT part of any supported API. @@ -75,6 +80,7 @@ public class TransTypes extends TreeTranslator { private Attr attr; private final Resolve resolve; private final CompileStates compileStates; + private final Target target; @SuppressWarnings("this-escape") protected TransTypes(Context context) { @@ -89,6 +95,7 @@ public class TransTypes extends TreeTranslator { resolve = Resolve.instance(context); annotate = Annotate.instance(context); attr = Attr.instance(context); + target = Target.instance(context); } /** Construct an attributed tree for a cast of expression to target type, @@ -539,6 +546,268 @@ public class TransTypes extends TreeTranslator { } } + @Override + public void visitReference(JCMemberReference tree) { + if (needsConversionToLambda(tree)) { + // Convert to a lambda, and process as such + MemberReferenceToLambda conv = new MemberReferenceToLambda(tree); + result = translate(conv.lambda()); + } else { + Type t = types.skipTypeVars(tree.expr.type, false); + Type receiverTarget = t.isCompound() ? erasure(tree.sym.owner.type) : erasure(t); + if (tree.kind == ReferenceKind.UNBOUND) { + tree.expr = make.Type(receiverTarget); + } else { + tree.expr = translate(tree.expr, receiverTarget); + } + if (!tree.type.isIntersection()) { + tree.type = erasure(tree.type); + } else { + tree.type = types.erasure(types.findDescriptorSymbol(tree.type.tsym).owner.type); + } + result = tree; + } + } + // where + boolean needsVarArgsConversion(JCMemberReference tree) { + return tree.varargsElement != null; + } + + /** + * @return Is this an array operation like clone() + */ + boolean isArrayOp(JCMemberReference tree) { + return tree.sym.owner == syms.arrayClass; + } + + boolean receiverAccessible(JCMemberReference tree) { + //hack needed to workaround 292 bug (7087658) + //when 292 issue is fixed we should remove this and change the backend + //code to always generate a method handle to an accessible method + return tree.ownerAccessible; + } + + /** + * Erasure destroys the implementation parameter subtype + * relationship for intersection types. + * Have similar problems for union types too. + */ + boolean interfaceParameterIsIntersectionOrUnionType(JCMemberReference tree) { + List tl = tree.getDescriptorType(types).getParameterTypes(); + for (; tl.nonEmpty(); tl = tl.tail) { + Type pt = tl.head; + if (isIntersectionOrUnionType(pt)) + return true; + } + return false; + } + + boolean isIntersectionOrUnionType(Type t) { + return switch (t.getKind()) { + case INTERSECTION, UNION -> true; + case TYPEVAR -> { + TypeVar tv = (TypeVar) t; + yield isIntersectionOrUnionType(tv.getUpperBound()); + } + default -> false; + }; + } + + private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference, + Symbol currentClass) { + return ((targetReference.flags() & PROTECTED) != 0 && + targetReference.packge() != currentClass.packge()); + } + + /** + * This method should be called only when target release <= 14 + * where LambdaMetaFactory does not spin nestmate classes. + * + * This method should be removed when --release 14 is not supported. + */ + boolean isPrivateInOtherClass(JCMemberReference tree) { + return (tree.sym.flags() & PRIVATE) != 0 && + !types.isSameType( + types.erasure(tree.sym.enclClass().asType()), + types.erasure(env.enclClass.sym.asType())); + } + + /** + * Does this reference need to be converted to a lambda + * (i.e. var args need to be expanded or "super" is used) + */ + boolean needsConversionToLambda(JCMemberReference tree) { + return interfaceParameterIsIntersectionOrUnionType(tree) || + tree.hasKind(ReferenceKind.SUPER) || + needsVarArgsConversion(tree) || + isArrayOp(tree) || + (!target.runtimeUseNestAccess() && isPrivateInOtherClass(tree)) || + isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, env.enclClass.sym) || + !receiverAccessible(tree) || + (tree.getMode() == ReferenceMode.NEW && + tree.kind != ReferenceKind.ARRAY_CTOR && + (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner())); + } + + /** + * Converts a method reference which cannot be used directly into a lambda + */ + private class MemberReferenceToLambda { + + private final JCMemberReference tree; + private final ListBuffer args = new ListBuffer<>(); + private final ListBuffer params = new ListBuffer<>(); + private final MethodSymbol owner = new MethodSymbol(0, names.empty, Type.noType, env.enclClass.sym); + + private JCExpression receiverExpression = null; + + MemberReferenceToLambda(JCMemberReference tree) { + this.tree = tree; + } + + JCExpression lambda() { + int prevPos = make.pos; + try { + make.at(tree); + + //body generation - this can be either a method call or a + //new instance creation expression, depending on the member reference kind + VarSymbol rcvr = addParametersReturnReceiver(); + JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) + ? expressionInvoke(rcvr) + : expressionNew(); + + JCLambda slam = make.Lambda(params.toList(), expr); + slam.target = tree.target; + slam.type = tree.type; + slam.pos = tree.pos; + slam.wasMethodReference = true; + if (receiverExpression != null) { + // use a let expression so that the receiver expression is evaluated eagerly + return make.at(tree.pos).LetExpr( + make.VarDef(rcvr, receiverExpression), slam).setType(tree.type); + } else { + return slam; + } + } finally { + make.at(prevPos); + } + } + + /** + * Generate the parameter list for the converted member reference. + * + * @return The receiver variable symbol, if any + */ + VarSymbol addParametersReturnReceiver() { + List descPTypes = tree.getDescriptorType(types).getParameterTypes(); + + // Determine the receiver, if any + VarSymbol rcvr; + switch (tree.kind) { + case BOUND: + // The receiver is explicit in the method reference + rcvr = new VarSymbol(SYNTHETIC, names.fromString("rec$"), tree.getQualifierExpression().type, owner); + rcvr.pos = tree.pos; + receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); + break; + case UNBOUND: + // The receiver is the first parameter, extract it and + // adjust the SAM and unerased type lists accordingly + rcvr = addParameter("rec$", descPTypes.head, false); + descPTypes = descPTypes.tail; + break; + default: + rcvr = null; + break; + } + List implPTypes = tree.sym.type.getParameterTypes(); + int implSize = implPTypes.size(); + int samSize = descPTypes.size(); + // Last parameter to copy from referenced method, exclude final var args + int last = needsVarArgsConversion(tree) ? implSize - 1 : implSize; + + for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { + // Use the descriptor parameter type + Type parmType = descPTypes.head; + addParameter("x$" + i, parmType, true); + + // Advance to the next parameter + implPTypes = implPTypes.tail; + descPTypes = descPTypes.tail; + } + // Flatten out the var args + for (int i = last; i < samSize; ++i) { + addParameter("xva$" + i, tree.varargsElement, true); + } + + return rcvr; + } + + /** + * determine the receiver of the method call - the receiver can + * be a type qualifier, the synthetic receiver parameter or 'super'. + */ + private JCExpression expressionInvoke(VarSymbol rcvr) { + JCExpression qualifier = + (rcvr != null) ? + make.Ident(rcvr) : + tree.getQualifierExpression(); + + //create the qualifier expression + JCFieldAccess select = make.Select(qualifier, tree.sym.name); + select.sym = tree.sym; + select.type = tree.referentType; + + //create the method call expression + JCExpression apply = make.Apply(List.nil(), select, + args.toList()).setType(tree.referentType.getReturnType()); + + TreeInfo.setVarargsElement(apply, tree.varargsElement); + return apply; + } + + /** + * Lambda body to use for a 'new'. + */ + private JCExpression expressionNew() { + if (tree.kind == ReferenceKind.ARRAY_CTOR) { + //create the array creation expression + JCNewArray newArr = make.NewArray( + make.Type(types.elemtype(tree.getQualifierExpression().type)), + List.of(make.Ident(params.first())), + null); + newArr.type = tree.getQualifierExpression().type; + return newArr; + } else { + //create the instance creation expression + //note that method reference syntax does not allow an explicit + //enclosing class (so the enclosing class is null) + // but this may need to be patched up later with the proxy for the outer this + JCNewClass newClass = make.NewClass(null, + List.nil(), + make.Type(tree.getQualifierExpression().type), + args.toList(), + null); + newClass.constructor = tree.sym; + newClass.constructorType = tree.sym.erasure(types); + newClass.type = tree.getQualifierExpression().type; + TreeInfo.setVarargsElement(newClass, tree.varargsElement); + return newClass; + } + } + + private VarSymbol addParameter(String name, Type p, boolean genArg) { + VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); + vsym.pos = tree.pos; + params.append(make.VarDef(vsym, null)); + if (genArg) { + args.append(make.Ident(vsym)); + } + return vsym; + } + } + public void visitSwitch(JCSwitch tree) { Type selsuper = types.supertype(tree.selector.type); boolean enumSwitch = selsuper != null && @@ -860,24 +1129,6 @@ public class TransTypes extends TreeTranslator { } } - public void visitReference(JCMemberReference tree) { - Type t = types.skipTypeVars(tree.expr.type, false); - Type receiverTarget = t.isCompound() ? erasure(tree.sym.owner.type) : erasure(t); - if (tree.kind == ReferenceKind.UNBOUND) { - tree.expr = make.Type(receiverTarget); - } else { - tree.expr = translate(tree.expr, receiverTarget); - } - if (!tree.type.isIntersection()) { - tree.type = erasure(tree.type); - } else { - tree.type = types.erasure(types.findDescriptorSymbol(tree.type.tsym).owner.type); - } - if (tree.varargsElement != null) - tree.varargsElement = erasure(tree.varargsElement); - result = tree; - } - public void visitTypeArray(JCArrayTypeTree tree) { tree.elemtype = translate(tree.elemtype, null); tree.type = erasure(tree.type); diff --git a/test/langtools/tools/javac/SuperInit/MrefDoubleTrans.java b/test/langtools/tools/javac/SuperInit/MrefDoubleTrans.java new file mode 100644 index 00000000000..aeddae455b2 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/MrefDoubleTrans.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, 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 8336320 + * @summary NullPointerException: Cannot invoke Type.getTag because type is null after JDK-8334037 + * @compile MrefDoubleTrans.java + */ +class MrefDoubleTrans { + public void f() { + Runnable r = new I()::m; + } + + class I { + void m(Object... xs) {} + } +}