From f0ec972a9a497f44d7ae1dc1012a2383d37f1fef Mon Sep 17 00:00:00 2001 From: Jan Lahoda <51319204+lahodaj@users.noreply.github.com> Date: Fri, 17 Jan 2025 18:03:53 +0100 Subject: [PATCH] Separate PatternType from MethodType (#13) * An experiment on PatternType. * Fixing test. * Fixing build. * Fixing tests. * Cleanup. --- .../com/sun/tools/javac/code/Printer.java | 6 + .../com/sun/tools/javac/code/Type.java | 122 ++++++++++++++++-- .../sun/tools/javac/code/TypeAnnotations.java | 6 + .../com/sun/tools/javac/code/TypeTag.java | 1 + .../com/sun/tools/javac/code/Types.java | 27 +++- .../com/sun/tools/javac/comp/Attr.java | 6 +- .../com/sun/tools/javac/comp/Flow.java | 2 +- .../com/sun/tools/javac/comp/Lower.java | 2 +- .../com/sun/tools/javac/comp/MemberEnter.java | 21 +-- .../com/sun/tools/javac/jvm/ClassReader.java | 4 +- .../com/sun/tools/javac/jvm/ClassWriter.java | 26 ++-- .../classes/com/sun/tools/javac/jvm/Code.java | 1 + .../com/sun/tools/javac/jvm/JNIWriter.java | 5 + test/langtools/tools/javac/lib/DPrinter.java | 7 + 14 files changed, 190 insertions(+), 46 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Printer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Printer.java index f59392c658b..ba1b5a0d14f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Printer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Printer.java @@ -250,6 +250,12 @@ public String visitMethodType(MethodType t, Locale locale) { visit(t.restype, locale); } + @Override + public String visitPatternType(PatternType t, Locale locale) { + return "(" + printMethodArgs(t.bindingtypes, false, locale) + ")" + + visit(t.restype, locale); + } + @Override public String visitPackageType(PackageType t, Locale locale) { return t.tsym.getQualifiedName().toString(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java index ae5a10e79a8..2c7073a2e64 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java @@ -285,15 +285,12 @@ protected boolean needsStripping() { @Override public Type visitMethodType(MethodType t, S s) { List argtypes = t.argtypes; - List bindingtypes = t.bindingtypes; Type restype = t.restype; List thrown = t.thrown; - List bindingtypes1 = bindingtypes != null ? visit(bindingtypes, s) : null; List argtypes1 = visit(argtypes, s); Type restype1 = visit(restype, s); List thrown1 = visit(thrown, s); if (argtypes1 == argtypes && - bindingtypes1 == bindingtypes && restype1 == restype && thrown1 == thrown) return t; else { @@ -303,7 +300,6 @@ protected boolean needsStripping() { return true; } }; - methodType.bindingtypes = bindingtypes1; return methodType; } } @@ -312,6 +308,22 @@ protected boolean needsStripping() { public Type visitForAll(ForAll t, S s) { return visit(t.qtype, s); } + + @Override + public Type visitPatternType(PatternType t, S s) { + List bindingtypes = t.bindingtypes; + List bindingtypes1 = visit(bindingtypes, s); + if (bindingtypes1 == bindingtypes) return t; + else { + PatternType patternType = new PatternType(bindingtypes1, /*XXX*/t.restype, t.tsym) { + @Override + protected boolean needsStripping() { + return true; + } + }; + return patternType; + } + } } /** map a type function over all immediate descendants of this type @@ -722,6 +734,8 @@ public static List filter(List ts, Predicate tf) { */ public MethodType asMethodType() { throw new AssertionError(); } + public PatternType asPatternType() { throw new AssertionError(); } + /** Complete loading all classes in this type. */ public void complete() {} @@ -1479,7 +1493,6 @@ public R accept(TypeVisitor v, P p) { public static class MethodType extends Type implements ExecutableType, LoadableConstant { public List argtypes; - public List bindingtypes; public Type restype; public List thrown; @@ -1528,7 +1541,7 @@ public String toString() { public List getParameterTypes() { return argtypes; } @DefinedBy(Api.LANGUAGE_MODEL) - public List getBindingTypes() { return bindingtypes; } + public List getBindingTypes() { return List.nil(); } @DefinedBy(Api.LANGUAGE_MODEL) public Type getReturnType() { return restype; } @@ -1542,7 +1555,6 @@ public Type getReceiverType() { public boolean isErroneous() { return isErroneous(argtypes) || - bindingtypes != null && isErroneous(bindingtypes) || restype != null && restype.isErroneous(); } @@ -1560,8 +1572,6 @@ public boolean contains(Type elem) { public void complete() { for (List l = argtypes; l.nonEmpty(); l = l.tail) l.head.complete(); - for (List l = bindingtypes; l.nonEmpty(); l = l.tail) - l.head.complete(); restype.complete(); recvtype.complete(); for (List l = thrown; l.nonEmpty(); l = l.tail) @@ -1923,6 +1933,99 @@ public R accept(TypeVisitor v, P p) { } } + public static class PatternType extends Type implements ExecutableType { + public List bindingtypes; + public Type restype; + + public PatternType(List bindingtypes, + Type restype, //TODO: + TypeSymbol methodClass) { + super(methodClass, List.nil()); + this.bindingtypes = bindingtypes; + this.restype = restype; + } + + @Override + public TypeTag getTag() { + return TypeTag.PATTERN; + } + + public R accept(Type.Visitor v, S s) { + return v.visitPatternType(this, s); + } + + /** The Java source which this type represents. + * + * XXX 06/09/99 iris This isn't correct Java syntax, but it probably + * should be. + */ + @DefinedBy(Api.LANGUAGE_MODEL) + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAnnotationsString(sb); + sb.append("(out"); + sb.append(bindingtypes); + sb.append(')'); + return sb.toString(); + } + + @DefinedBy(Api.LANGUAGE_MODEL) + public List getParameterTypes() { return List.nil(); } + + @DefinedBy(Api.LANGUAGE_MODEL) + public List getBindingTypes() { return bindingtypes; } + + @DefinedBy(Api.LANGUAGE_MODEL) + public Type getReturnType() { return restype; } + @DefinedBy(Api.LANGUAGE_MODEL) + public Type getReceiverType() { + return Type.noType; + } + @DefinedBy(Api.LANGUAGE_MODEL) + public List getThrownTypes() { return List.nil(); } + + @Override + public PatternType asPatternType() { return this; } + + public boolean isErroneous() { + return + bindingtypes != null && isErroneous(bindingtypes); + } + + @Override + public int poolTag() { + return ClassFile.CONSTANT_MethodType; //TODO + } + + public boolean contains(Type elem) { + return elem.equalsIgnoreMetadata(this); + } + + public void complete() { + for (List l = bindingtypes; l.nonEmpty(); l = l.tail) + l.head.complete(); + } + + @DefinedBy(Api.LANGUAGE_MODEL) + public List getTypeVariables() { + return List.nil(); + } + + public TypeSymbol asElement() { + return null; + } + + @DefinedBy(Api.LANGUAGE_MODEL) + public TypeKind getKind() { + return TypeKind.EXECUTABLE; + } + + @DefinedBy(Api.LANGUAGE_MODEL) + public R accept(TypeVisitor v, P p) { + return v.visitExecutable(this, p); + } + } + /** A class for inference variables, for use during method/diamond type * inference. An inference variable has upper/lower bounds and a set * of equality constraints. Such bounds are set during subtyping, type-containment, @@ -2444,6 +2547,7 @@ public interface Visitor { R visitWildcardType(WildcardType t, S s); R visitArrayType(ArrayType t, S s); R visitMethodType(MethodType t, S s); + R visitPatternType(PatternType t, S s); R visitPackageType(PackageType t, S s); R visitModuleType(ModuleType t, S s); R visitTypeVar(TypeVar t, S s); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index ddbfd83c54c..a45682587e3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -633,6 +633,12 @@ public Type visitMethodType(MethodType t, List s) { return t; } + @Override + public Type visitPatternType(Type.PatternType t, List s) { + // Impossible? + return t; + } + @Override public Type visitPackageType(PackageType t, List s) { // Impossible? diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java index 51d3deec88b..223c4d44c5f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java @@ -84,6 +84,7 @@ public enum TypeTag { /** The tag of all (monomorphic) method types. */ METHOD, + PATTERN, /** The tag of all package "types". */ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index 750b7d2d1af..01ac82940d5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -1443,6 +1443,11 @@ public Boolean visitMethodType(MethodType t, Type s) { return hasSameArgs(t, s) && visit(t.getReturnType(), s.getReturnType()); } + @Override + public Boolean visitPatternType(PatternType t, Type s) { + return hasSameArgs(t, s); + } + @Override public Boolean visitPackageType(PackageType t, Type s) { return t == s; @@ -3299,12 +3304,16 @@ public Boolean visitType(Type t, Type s) { @Override public Boolean visitMethodType(MethodType t, Type s) { if (s.hasTag(METHOD)) { - if (t.bindingtypes != null && t.bindingtypes.size() > 0) return containsTypeEquivalent(t.bindingtypes, s.getBindingTypes()); - else return containsTypeEquivalent(t.argtypes, s.getParameterTypes()); + return containsTypeEquivalent(t.argtypes, s.getParameterTypes()); } return false; } + @Override + public Boolean visitPatternType(PatternType t, Type s) { + return containsTypeEquivalent(t.bindingtypes, s.getBindingTypes()); + } + @Override public Boolean visitForAll(ForAll t, Type s) { if (!s.hasTag(FORALL)) @@ -4941,6 +4950,7 @@ public abstract static class DefaultTypeVisitor implements Type.Visitor 0) { - assembleSig(mt.bindingtypes); - } else { - assembleSig(mt.argtypes); - } + assembleSig(mt.argtypes); append(')'); assembleSig(mt.restype); if (hasTypeVar(mt.thrown)) { @@ -5214,6 +5220,13 @@ public void assembleSig(Type type) { } } break; + case PATTERN: + PatternType pt = (PatternType) type; + append('('); + assembleSig(pt.bindingtypes); + append(')'); + assembleSig(pt.restype); + break; case WILDCARD: { Type.WildcardType ta = (Type.WildcardType) type; switch (ta.kind) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 8dfa1997888..d12a04294ee 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -74,6 +74,7 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Flags.ANNOTATION; import static com.sun.tools.javac.code.Flags.BLOCK; +import static com.sun.tools.javac.code.Flags.PATTERN; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.TypeTag.*; @@ -4592,9 +4593,8 @@ private List patternDeclarationCandidatesWithArity(Type site, int .map(rc -> types.memberType(site, rc)) .collect(List.collector()); - MethodType mt = new MethodType(List.nil(), syms.voidType, List.nil(), syms.methodClass); - mt.bindingtypes = recordComponents; - patternDeclarations = patternDeclarations.prepend(new MethodSymbol(PUBLIC | SYNTHETIC | PATTERN, ((ClassSymbol) site.tsym).name, mt, site.tsym)); + PatternType pt = new PatternType(recordComponents, syms.voidType, syms.methodClass); + patternDeclarations = patternDeclarations.prepend(new MethodSymbol(PUBLIC | SYNTHETIC | PATTERN, ((ClassSymbol) site.tsym).name, pt, site.tsym)); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 192242fe00a..8ce2fdf38af 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -3592,7 +3592,7 @@ public PatternDescription makePatternDescription(Type selectorType, JCPattern pa MethodSymbol patternDeclaration = ((JCRecordPattern) pattern).patternDeclaration; if (!record.type.isErroneous() && patternDeclaration != null) { - componentTypes = patternDeclaration.type.asMethodType().bindingtypes.toArray(Type[]::new); + componentTypes = patternDeclaration.type.asPatternType().bindingtypes.toArray(Type[]::new); } else { componentTypes = record.nested.map(t -> types.createErrorType(t.type)).toArray(s -> new Type[s]);; 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 7011a66d821..dcce1f9b0a4 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 @@ -2653,12 +2653,12 @@ public void visitMethodDef(JCMethodDecl tree) { m.params = m.params.prepend(implicitThisParam.sym); Type olderasure = m.erasure(types); + //create an external type for the pattern: var mt = new MethodType( olderasure.getParameterTypes().prepend(tree.sym.owner.type), olderasure.getReturnType(), olderasure.getThrownTypes(), syms.methodClass); - mt.bindingtypes = olderasure.getBindingTypes(); m.erasure_field = mt; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java index 8433383c9d4..a9ef6ed5196 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -156,17 +156,20 @@ Type signature(MethodSymbol msym, } thrownbuf.append(exc); } - MethodType mtype = new MethodType(argbuf.toList(), - restype, - thrownbuf.toList(), - syms.methodClass); - if (bindings != null) { - mtype.bindingtypes = bindingsbuf.toList(); - } + if (msym.isPattern()) { + Assert.check(params.isEmpty()); + return new PatternType(bindingsbuf.toList(), restype, syms.methodClass); + } else { + Assert.check(bindings == null); + MethodType mtype = new MethodType(argbuf.toList(), + restype, + thrownbuf.toList(), + syms.methodClass); - mtype.recvtype = recvtype; + mtype.recvtype = recvtype; - return tvars.isEmpty() ? mtype : new ForAll(tvars, mtype); + return tvars.isEmpty() ? mtype : new ForAll(tvars, mtype); + } } /* ******************************************************************** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 531c968526b..65ef70c8c82 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -1406,7 +1406,7 @@ protected void read(Symbol sym, int attrLen) { // todo: check if special handling is needed similar to generic methods for binding types - msym.type.asMethodType().bindingtypes = patternType.getParameterTypes(); + msym.type = new PatternType(patternType.getParameterTypes(), syms.voidType, syms.methodClass); } } }, @@ -2776,7 +2776,7 @@ MethodSymbol readMethod() { } void validateMethodType(Name name, Type t) { - if ((!t.hasTag(TypeTag.METHOD) && !t.hasTag(TypeTag.FORALL)) || + if ((!t.hasTag(TypeTag.METHOD) && !t.hasTag(TypeTag.FORALL) && !t.hasTag(TypeTag.PATTERN)) || (name == names.init && !t.getReturnType().hasTag(TypeTag.VOID))) { throw badClassFile("method.descriptor.invalid", name); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java index b4c1c2e5dcb..a8fb97459ba 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java @@ -360,14 +360,17 @@ int writeMemberAttrs(Symbol sym, boolean isRecordComponent, boolean fromPattern) acount = writeFlagAttrs(sym.flags()); } long flags = sym.flags(); - boolean needsSignature = !types.isSameType(sym.type, sym.erasure(types)) || - poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()); - if (((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC && - (flags & ANONCONSTR) == 0 && - needsSignature) || - (needsSignature && - fromPattern && - sym.isPattern())) { + boolean needsSignature; + if (fromPattern && sym.isPattern()) { + needsSignature = !types.isSameType(sym.type, types.erasure(sym.type)) || + poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()); + } else { + needsSignature = !types.isSameType(sym.type, sym.erasure(types)) || + poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()); + needsSignature &= (flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC && + (flags & ANONCONSTR) == 0; + } + if (needsSignature) { // note that a local class with captured variables // will get a signature attribute int alenIdx = writeAttr(names.Signature); @@ -887,12 +890,7 @@ int writePatternAttribute(MethodSymbol m) { databuf.appendChar(poolWriter.putName(m.name)); databuf.appendChar(PatternFlags.value(m.patternFlags)); - MethodType mt = new MethodType( - m.type.getBindingTypes(), - m.type.asMethodType().restype, - m.type.getThrownTypes(), - m.type.tsym); - databuf.appendChar(poolWriter.putDescriptor(mt)); + databuf.appendChar(poolWriter.putDescriptor(m.type)); int acountIdx = beginAttrs(); int acount = 0; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java index 9dab7507cb1..6d7968895ce 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java @@ -255,6 +255,7 @@ public static int typecode(Type type) { case CLASS: case ARRAY: case METHOD: + case PATTERN: case BOT: case TYPEVAR: case UNINITIALIZED_THIS: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java index 2de0e330796..1362ff9a12e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java @@ -675,6 +675,11 @@ public R visitMethodType(Type.MethodType t, P p) { return defaultAction(t, p); } + @Override + public R visitPatternType(Type.PatternType t, P p) { + return defaultAction(t, p); + } + @Override public R visitPackageType(Type.PackageType t, P p) { return defaultAction(t, p); diff --git a/test/langtools/tools/javac/lib/DPrinter.java b/test/langtools/tools/javac/lib/DPrinter.java index 6fa2f17dc67..1e05e71f27b 100644 --- a/test/langtools/tools/javac/lib/DPrinter.java +++ b/test/langtools/tools/javac/lib/DPrinter.java @@ -1343,6 +1343,13 @@ public Void visitMethodType(MethodType type, Void ignore) { return visitType(type, null); } + @Override + public Void visitPatternType(PatternType type, Void ignore) { + printList("bindingtypes", type.bindingtypes); + printType("restype", type.restype, Details.FULL); + return visitType(type, null); + } + public Void visitModuleType(ModuleType type, Void ignore) { return visitType(type, null); }