Skip to content

Commit

Permalink
Decouple params and bindings lists for methods
Browse files Browse the repository at this point in the history
  • Loading branch information
biboudis committed Apr 8, 2024
1 parent 0df5fc9 commit ca13242
Show file tree
Hide file tree
Showing 17 changed files with 174 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ public enum ElementKind {
METHOD,
/** A constructor. */
CONSTRUCTOR,

// todo: PATTERN_DECLARATION

/** A static initializer. */
STATIC_INIT,
/** An instance initializer. */
Expand Down Expand Up @@ -120,6 +123,8 @@ public enum ElementKind {
/**
* A binding variable in a pattern.
* @since 16
*
* todo: think about reusing it for bindings of pattern declarations
*/
BINDING_VARIABLE;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ public interface ExecutableElement extends Element, Parameterizable {
*/
List<? extends VariableElement> getParameters();

/**
* Returns the binding parameters of this executable.
* They are returned in declaration order.
*
* @return the binding parameters,
* or an empty list if there are none or is not a pattern declaration.
*/
List<? extends VariableElement> getBindings();

/**
* Returns the receiver type of this executable,
* or {@link javax.lang.model.type.NoType NoType} with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ public interface ExecutableType extends TypeMirror {
*/
List<? extends TypeMirror> getParameterTypes();

/**
* Returns the types of this executable's binding parameters.
*
* @return the types of this executable's binding parameters,
* or an empty list if there are none or is not a pattern declaration.
*/
List<? extends TypeMirror> getBindingTypes();

/**
* Returns the receiver type of this executable,
* or {@link javax.lang.model.type.NoType NoType} with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ public boolean isConstructor() {
return name == name.table.names.init;
}

/** Is this symbol a matcher?
/** Is this symbol a pattern declaration?
*/
public boolean isPattern() {
return (flags() & PATTERN) != 0;
Expand Down Expand Up @@ -1992,6 +1992,9 @@ public static class MethodSymbol extends Symbol implements ExecutableElement {
/** The parameters of the method. */
public List<VarSymbol> params = null;

/** The bindings of the method if it is a pattern declaration. */
public List<VarSymbol> bindings = null;

/** For an annotation type element, its default value if any.
* The value is null if none appeared in the method
* declaration.
Expand Down Expand Up @@ -2065,7 +2068,7 @@ public Name externalName(Types types) {
/** TODO: improve perf
* e.g., Point\%Ljava\|lang\|Integer\?\%Ljava\|lang\|Integer\?(Point)
*/
Name postFix = name.table.names.fromString(params().map(param -> {
Name postFix = name.table.names.fromString(bindings().map(param -> {
var g = new UnSharedSignatureGenerator(types, name.table.names);
g.assembleSig(param.erasure(types));
return name.table.names.fromString(g.toName().toString().replace("/", "\\\u007C").replace(";", "\\\u003F"));
Expand Down Expand Up @@ -2349,6 +2352,23 @@ public List<VarSymbol> params() {
return params;
}

public List<VarSymbol> bindings() {
owner.complete();
if (bindings == null) {
ListBuffer<VarSymbol> newBindings = new ListBuffer<>();
int i = 0;
for (Type t : type.getParameterTypes()) {
Name bindingName = name.table.fromString("bind" + i);
VarSymbol binding = new VarSymbol(MATCH_BINDING, bindingName, t, this);
newBindings.append(binding);
i++;
}
bindings = newBindings.toList();
}
Assert.checkNonNull(bindings);
return bindings;
}

public Symbol asMemberOf(Type site, Types types) {
return new MethodSymbol(flags_field, name, types.memberType(site, this), owner);
}
Expand Down Expand Up @@ -2380,6 +2400,11 @@ public List<VarSymbol> getParameters() {
return params();
}

@DefinedBy(Api.LANGUAGE_MODEL)
public List<VarSymbol> getBindings() {
return bindings();
}

@DefinedBy(Api.LANGUAGE_MODEL)
public boolean isVarArgs() {
return (flags() & VARARGS) != 0;
Expand Down
26 changes: 20 additions & 6 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -285,20 +285,27 @@ protected boolean needsStripping() {
@Override
public Type visitMethodType(MethodType t, S s) {
List<Type> argtypes = t.argtypes;
List<Type> bindingtypes = t.bindingtypes;
Type restype = t.restype;
List<Type> thrown = t.thrown;
List<Type> bindingtypes1 = bindingtypes != null ? visit(bindingtypes, s) : null;
List<Type> argtypes1 = visit(argtypes, s);
Type restype1 = visit(restype, s);
List<Type> thrown1 = visit(thrown, s);
if (argtypes1 == argtypes &&
bindingtypes1 == bindingtypes &&
restype1 == restype &&
thrown1 == thrown) return t;
else return new MethodType(argtypes1, restype1, thrown1, t.tsym) {
@Override
protected boolean needsStripping() {
return true;
}
};
else {
MethodType methodType = new MethodType(argtypes1, restype1, thrown1, t.tsym) {
@Override
protected boolean needsStripping() {
return true;
}
};
methodType.bindingtypes = bindingtypes1;
return methodType;
}
}

@Override
Expand Down Expand Up @@ -594,6 +601,7 @@ public String argtypes(boolean varargs) {
public List<Type> getTypeArguments() { return List.nil(); }
public Type getEnclosingType() { return null; }
public List<Type> getParameterTypes() { return List.nil(); }
public List<Type> getBindingTypes() { return List.nil(); }
public Type getReturnType() { return null; }
public Type getReceiverType() { return null; }
public List<Type> getThrownTypes() { return List.nil(); }
Expand Down Expand Up @@ -1470,6 +1478,7 @@ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
public static class MethodType extends Type implements ExecutableType, LoadableConstant {

public List<Type> argtypes;
public List<Type> bindingtypes;
public Type restype;
public List<Type> thrown;

Expand Down Expand Up @@ -1516,6 +1525,10 @@ public String toString() {

@DefinedBy(Api.LANGUAGE_MODEL)
public List<Type> getParameterTypes() { return argtypes; }

@DefinedBy(Api.LANGUAGE_MODEL)
public List<Type> getBindingTypes() { return bindingtypes; }

@DefinedBy(Api.LANGUAGE_MODEL)
public Type getReturnType() { return restype; }
@DefinedBy(Api.LANGUAGE_MODEL)
Expand Down Expand Up @@ -1831,6 +1844,7 @@ public DelegatedType(TypeTag tag, Type qtype,
public List<Type> getTypeArguments() { return qtype.getTypeArguments(); }
public Type getEnclosingType() { return qtype.getEnclosingType(); }
public List<Type> getParameterTypes() { return qtype.getParameterTypes(); }
public List<Type> getBindingTypes() { return qtype.getBindingTypes(); }
public Type getReturnType() { return qtype.getReturnType(); }
public Type getReceiverType() { return qtype.getReceiverType(); }
public List<Type> getThrownTypes() { return qtype.getThrownTypes(); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3286,8 +3286,11 @@ public Boolean visitType(Type t, Type s) {

@Override
public Boolean visitMethodType(MethodType t, Type s) {
return s.hasTag(METHOD)
&& containsTypeEquivalent(t.argtypes, s.getParameterTypes());
if (s.hasTag(METHOD)) {
if (t.tsym.isPattern()) return containsTypeEquivalent(t.bindingtypes, s.getBindingTypes());
else return containsTypeEquivalent(t.argtypes, s.getParameterTypes());
}
return false;
}

@Override
Expand Down
23 changes: 12 additions & 11 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
Original file line number Diff line number Diff line change
Expand Up @@ -2372,21 +2372,22 @@ public void visitMatch(JCMatch tree) {
Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
tree.meth = localEnv.enclMethod;

List<Type> parameterTypes = tree.meth.sym.type.getParameterTypes();
List<Type> bindingTypes = tree.meth.sym.type.getBindingTypes();
List<JCExpression> args = tree.args;

if (parameterTypes.size() != args.size()) {
log.error(tree.pos(), Errors.MatchNotMatchingPatternDeclarationSignature);
}

if (!tree.meth.sym.isPattern()) {
log.error(tree.pos(), Errors.MatchOutsidePatternDeclaration);
return;
}

if (bindingTypes.size() != args.size()) {
log.error(tree.pos(), Errors.MatchNotMatchingPatternDeclarationSignature);
}

while (parameterTypes.nonEmpty() && args.nonEmpty()) {
attribExpr(args.head, localEnv, parameterTypes.head);
while (bindingTypes.nonEmpty() && args.nonEmpty()) {
attribExpr(args.head, localEnv, bindingTypes.head);

parameterTypes = parameterTypes.tail;
bindingTypes = bindingTypes.tail;
args = args.tail;
}

Expand Down Expand Up @@ -4300,7 +4301,7 @@ public void visitRecordPattern(JCRecordPattern tree) {
List<Type> patternTypes = patternTypesBuffer.toList();

var matchersIt = site.tsym.members()
.getSymbols(sym -> sym.isPattern() && sym.type.getParameterTypes().size() == nestedPatternCount)
.getSymbols(sym -> sym.isPattern() && sym.type.getBindingTypes().size() == nestedPatternCount)
.iterator();
List<MethodSymbol> matchers = Stream.generate(() -> null)
.takeWhile(x -> matchersIt.hasNext())
Expand All @@ -4314,7 +4315,7 @@ public void visitRecordPattern(JCRecordPattern tree) {
for (MethodSymbol matcher : matchers) {
int scoreForMatcher = 0;

List<Type> matcherComponentTypes = matcher.getParameters()
List<Type> matcherComponentTypes = matcher.getBindings()
.stream()
.map(rc -> types.memberType(site, rc))
.map(t -> types.upward(t, types.captures(t)).baseType())
Expand Down Expand Up @@ -4354,7 +4355,7 @@ public void visitRecordPattern(JCRecordPattern tree) {
MethodSymbol matcher = matchers.get(indexOfMaxScore);
tree.matcher = matcher;

expectedRecordTypes = types.memberType(site, matcher).getParameterTypes();
expectedRecordTypes = types.memberType(site, matcher).getBindingTypes();
}
} else if (((ClassSymbol) site.tsym).isRecord()) {
ClassSymbol record = (ClassSymbol) site.tsym;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4157,6 +4157,8 @@ boolean checkUnique(DiagnosticPosition pos, Symbol sym, Scope s) {
duplicateErasureError(pos, sym, byName);
sym.flags_field |= CLASH;
return true;
} else if (sym.isPattern() && byName.isPattern() && types.hasSameArgs(sym.type, byName.type, false)) {
return true;
} else if ((sym.flags() & MATCH_BINDING) != 0 &&
(byName.flags() & MATCH_BINDING) != 0 &&
(byName.flags() & MATCH_BINDING_TO_OUTER) == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3284,8 +3284,9 @@ public void visitAssert(JCAssert tree) {

public void visitApply(JCMethodInvocation tree) {
Symbol meth = TreeInfo.symbol(tree.meth);
List<Type> argtypes = meth.isPattern() ? List.of(tree.args.head.type)
: meth.type.getParameterTypes();
List<Type> argtypes = meth.isPattern()
? List.of(tree.args.head.type)
: meth.type.getParameterTypes();
if (meth.name == names.init && meth.owner == syms.enumSym)
argtypes = argtypes.tail.tail;
tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,6 @@ public void visitMethodDef(JCMethodDecl tree) {
m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
tree.sym = m;

// if (tree.sym.isMatcher()) {
// m.flags_field |= SYNTHETIC;
// }

//if this is a default method, add the DEFAULT flag to the enclosing interface
if ((tree.mods.flags & DEFAULT) != 0) {
m.owner.flags_field |= DEFAULT;
Expand All @@ -201,10 +197,15 @@ public void visitMethodDef(JCMethodDecl tree) {
DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
try {
// Compute the method type
m.type = signature(m, tree.typarams, tree.params,
Type t = signature(m, tree.typarams, tree.params,
tree.restype, tree.recvparam,
tree.thrown,
localEnv);
if (t instanceof MethodType mt && m.isPattern()) {
mt.bindingtypes = mt.argtypes;
mt.argtypes = List.nil();
}
m.type = t;
} finally {
deferredLintHandler.setPos(prevLintPos);
}
Expand All @@ -220,7 +221,14 @@ public void visitMethodDef(JCMethodDecl tree) {
JCVariableDecl param = lastParam = l.head;
params.append(Assert.checkNonNull(param.sym));
}
m.params = params.toList();

if (m.isPattern()) {
m.bindings = params.toList();
m.params = List.nil();
} else {
m.params = params.toList();
m.bindings = List.nil();
}

// mark the method varargs, if necessary
if (lastParam != null && (lastParam.mods.flags & Flags.VARARGS) != 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,11 +298,14 @@ private UnrolledRecordPattern unrollRecordPattern(JCRecordPattern recordPattern)
//$record $r; type-test-of($nestedPattern1) && type-test-of($nestedPattern2) && ... &&
// nested-conditions-of($nestedPattern1) && nested-conditions-of($nestedPattern2)

// A record pattern that comes with a matcher is desugared into the following structure (utilizing DynamicVarSymbols)
// if (o instanceof Matcher $m && Matcher."Matcher$Ljava\\|lang\\|String\\?$I"($m)) instanceof Object unmatched) {
// MethodType methodType = MethodType.methodType(Object.class, String.class, int.class); // represented as a Constant_MethodType_info
// os = (String) Carriers.component(methodType, 0).invoke(unmatched); // where Carriers.component(methodType, 0) is a DynamicVarSymbol
// oi = (int) Carriers.component(methodType, 1).invoke(unmatched); // where Carriers.component(methodType, 1) is a DynamicVarSymbol
// A record pattern that comes with a pattern declaration is desugared into the
// following structure (utilizing DynamicVarSymbols).
//
// if (o instanceof Matcher $m$1 &&
// Matcher."Matcher$Ljava\\|lang\\|String\\?$I"($m$1)) instanceof Object unmatched) {
// MethodType methodType = MethodType.methodType(Object.class, String.class, int.class); // represented as a Constant_MethodType_info
// os = (String) Carriers.component(methodType, 0).invoke($m$1); // where Carriers.component(methodType, 0) is a DynamicVarSymbol
// oi = (int) Carriers.component(methodType, 1).invoke($m$1); // where Carriers.component(methodType, 1) is a DynamicVarSymbol
// ...
// }
Type recordType = recordPattern.type.tsym.erasure(types);
Expand All @@ -320,18 +323,18 @@ private UnrolledRecordPattern unrollRecordPattern(JCRecordPattern recordPattern)
JCExpression secondLevelChecks = null;
int index = -1; // needed for the Carriers.component in the case of a matcher

BindingSymbol unmatched = null;
BindingSymbol mSymbol = null;
MethodSymbol carriersComponentCallSym = null;

if (recordPattern.matcher != null) {
unmatched = new BindingSymbol(Flags.SYNTHETIC,
mSymbol = new BindingSymbol(Flags.SYNTHETIC,
names.fromString(target.syntheticNameChar() + "m" + target.syntheticNameChar() + variableIndex++), syms.objectType,
currentMethodSym);
JCVariableDecl unmatchedVar = make.VarDef(unmatched, null);
JCVariableDecl mVar = make.VarDef(mSymbol, null);
JCExpression nullCheck = make.TypeTest(
make.App(make.Select(make.Ident(recordPattern.matcher.owner), recordPattern.matcher),
List.of(make.Ident(tempBind))).setType(syms.objectType),
make.BindingPattern(unmatchedVar).setType(unmatched.type)).setType(syms.booleanType);
make.BindingPattern(mVar).setType(mSymbol.type)).setType(syms.booleanType);

firstLevelChecks = nullCheck;

Expand All @@ -357,7 +360,7 @@ private UnrolledRecordPattern unrollRecordPattern(JCRecordPattern recordPattern)
* Generate invoke call for component X
* component$X.invoke(carrier);
* */
List<Type> params = recordPattern.matcher.params
List<Type> params = recordPattern.matcher.bindings
.map(v -> types.erasure(v.type));

MethodType methodType = new MethodType(params, syms.objectType, List.nil(), syms.methodClass);
Expand All @@ -371,7 +374,7 @@ private UnrolledRecordPattern unrollRecordPattern(JCRecordPattern recordPattern)
carriersComponentCallSym.asHandle(),
carriersComponentParams.toArray(LoadableConstant[]::new));

List<JCExpression> invokeComponentParams = List.of(make.Ident(unmatched));
List<JCExpression> invokeComponentParams = List.of(make.Ident(mSymbol));

MethodSymbol invokeComponentCallSym =
rs.resolveInternalMethod(recordPattern.pos(),
Expand Down
Loading

0 comments on commit ca13242

Please sign in to comment.