8315457: Implement JEP 459: String Templates (Second Preview)
Reviewed-by: jlahoda, alanb, vromero
This commit is contained in:
parent
5522656af7
commit
9902d2eb17
@ -46,7 +46,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.misc.CarrierThreadLocal;
|
||||
import jdk.internal.module.ServicesCatalog;
|
||||
import jdk.internal.reflect.ConstantPool;
|
||||
@ -420,19 +419,16 @@ public interface JavaLangAccess {
|
||||
/**
|
||||
* Get the coder for the supplied character.
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
|
||||
long stringConcatCoder(char value);
|
||||
|
||||
/**
|
||||
* Update lengthCoder for StringBuilder.
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
|
||||
long stringBuilderConcatMix(long lengthCoder, StringBuilder sb);
|
||||
|
||||
/**
|
||||
* Prepend StringBuilder content.
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
|
||||
*/
|
||||
long stringBuilderConcatPrepend(long lengthCoder, byte[] buf, StringBuilder sb);
|
||||
|
||||
/**
|
||||
|
@ -67,8 +67,7 @@ public @interface PreviewFeature {
|
||||
// not used, but required for interim javac to not warn.
|
||||
VIRTUAL_THREADS,
|
||||
FOREIGN,
|
||||
|
||||
@JEP(number=430, title="String Templates")
|
||||
@JEP(number=459, title="String Templates", status="Second Preview")
|
||||
STRING_TEMPLATES,
|
||||
@JEP(number=445, title="Unnamed Classes and Instance Main Methods")
|
||||
UNNAMED_CLASSES,
|
||||
|
@ -177,6 +177,7 @@ public interface Tree {
|
||||
|
||||
/**
|
||||
* Used for instances of {@link StringTemplateTree}.
|
||||
* @since 21
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true)
|
||||
TEMPLATE(StringTemplateTree.class),
|
||||
|
@ -264,6 +264,7 @@ public interface TreeVisitor<R,P> {
|
||||
* @param node the node being visited
|
||||
* @param p a parameter value
|
||||
* @return a result value
|
||||
* @since 21
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true)
|
||||
R visitStringTemplate(StringTemplateTree node, P p);
|
||||
|
@ -634,6 +634,7 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
|
||||
* @param node {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of {@code defaultAction}
|
||||
* @since 21
|
||||
*/
|
||||
@Override
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true)
|
||||
|
@ -783,6 +783,7 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
|
||||
* @param node {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of scanning
|
||||
* @since 21
|
||||
*/
|
||||
@Override
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true)
|
||||
|
@ -5024,12 +5024,11 @@ public class Attr extends JCTree.Visitor {
|
||||
|
||||
public void visitStringTemplate(JCStringTemplate tree) {
|
||||
JCExpression processor = tree.processor;
|
||||
Type resultType = syms.stringTemplateType;
|
||||
|
||||
if (processor != null) {
|
||||
resultType = attribTree(processor, env, new ResultInfo(KindSelector.VAL, Type.noType));
|
||||
resultType = chk.checkProcessorType(processor, resultType, env);
|
||||
}
|
||||
Type processorType = attribTree(processor, env, new ResultInfo(KindSelector.VAL, Type.noType));
|
||||
chk.checkProcessorType(processor, processorType, env);
|
||||
Type processMethodType = getProcessMethodType(tree, processorType);
|
||||
tree.processMethodType = processMethodType;
|
||||
Type resultType = processMethodType.getReturnType();
|
||||
|
||||
Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
|
||||
|
||||
@ -5039,10 +5038,16 @@ public class Attr extends JCTree.Visitor {
|
||||
|
||||
tree.type = resultType;
|
||||
result = resultType;
|
||||
|
||||
check(tree, resultType, KindSelector.VAL, resultInfo);
|
||||
}
|
||||
|
||||
private Type getProcessMethodType(JCStringTemplate tree, Type processorType) {
|
||||
MethodSymbol processSymbol = rs.resolveInternalMethod(tree.pos(),
|
||||
env, types.skipTypeVars(processorType, false),
|
||||
names.process, List.of(syms.stringTemplateType), List.nil());
|
||||
return types.memberType(processorType, processSymbol);
|
||||
}
|
||||
|
||||
public void visitTypeIdent(JCPrimitiveTypeTree tree) {
|
||||
result = check(tree, syms.typeOfTag[tree.typetag.ordinal()], KindSelector.TYP, resultInfo);
|
||||
}
|
||||
|
@ -4370,8 +4370,7 @@ public class Check {
|
||||
if (typeArguments.size() == 2) {
|
||||
resultType = typeArguments.head;
|
||||
} else {
|
||||
log.error(DiagnosticFlag.RESOLVE_ERROR, processor.pos,
|
||||
Errors.ProcessorTypeCannotBeARawType(processorType.tsym));
|
||||
resultType = syms.objectType;
|
||||
}
|
||||
} else {
|
||||
log.error(DiagnosticFlag.RESOLVE_ERROR, processor.pos,
|
||||
|
@ -1678,23 +1678,8 @@ public class Flow {
|
||||
|
||||
@Override
|
||||
public void visitStringTemplate(JCStringTemplate tree) {
|
||||
JCExpression processor = tree.processor;
|
||||
|
||||
if (processor != null) {
|
||||
scan(processor);
|
||||
Type interfaceType = types.asSuper(processor.type, syms.processorType.tsym);
|
||||
|
||||
if (interfaceType != null) {
|
||||
List<Type> typeArguments = interfaceType.getTypeArguments();
|
||||
|
||||
if (typeArguments.size() == 2) {
|
||||
Type throwType = typeArguments.tail.head;
|
||||
|
||||
if (throwType != null) {
|
||||
markThrown(tree, throwType);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Type thrown : tree.processMethodType.getThrownTypes()) {
|
||||
markThrown(tree, thrown);
|
||||
}
|
||||
|
||||
scan(tree.expressions);
|
||||
|
@ -254,7 +254,12 @@ public final class TransLiterals extends TreeTranslator {
|
||||
}
|
||||
|
||||
boolean isNamedProcessor(Name name) {
|
||||
if (processor instanceof JCIdent ident && ident.sym instanceof VarSymbol varSym) {
|
||||
Symbol sym = switch (processor) {
|
||||
case JCIdent ident -> ident.sym;
|
||||
case JCFieldAccess access -> access.sym;
|
||||
default -> null;
|
||||
};
|
||||
if (sym instanceof VarSymbol varSym) {
|
||||
if (varSym.flags() == (Flags.PUBLIC | Flags.FINAL | Flags.STATIC) &&
|
||||
varSym.name == name &&
|
||||
types.isSameType(varSym.owner.type, syms.stringTemplateType)) {
|
||||
@ -265,8 +270,7 @@ public final class TransLiterals extends TreeTranslator {
|
||||
}
|
||||
|
||||
boolean isLinkageProcessor() {
|
||||
return processor != null &&
|
||||
!useValuesList &&
|
||||
return !useValuesList &&
|
||||
types.isSubtype(processor.type, syms.linkageType) &&
|
||||
processor.type.isFinal() &&
|
||||
TreeInfo.symbol(processor) instanceof VarSymbol varSymbol &&
|
||||
@ -278,7 +282,7 @@ public final class TransLiterals extends TreeTranslator {
|
||||
JCExpression result;
|
||||
make.at(tree.pos);
|
||||
|
||||
if (processor == null || isNamedProcessor(names.RAW)) {
|
||||
if (isNamedProcessor(names.RAW)) {
|
||||
result = newStringTemplate();
|
||||
} else if (isNamedProcessor(names.STR)) {
|
||||
result = concatExpression(fragments, expressions);
|
||||
|
@ -1354,10 +1354,6 @@ compiler.err.text.block.template.is.not.well.formed=\
|
||||
compiler.err.processor.missing.from.string.template.expression=\
|
||||
processor missing from string template expression
|
||||
|
||||
# 0: symbol
|
||||
compiler.err.processor.type.cannot.be.a.raw.type=\
|
||||
processor type cannot be a raw type: {0}
|
||||
|
||||
# 0: symbol
|
||||
compiler.err.not.a.processor.type=\
|
||||
not a processor type: {0}
|
||||
|
@ -2488,6 +2488,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public JCExpression processor;
|
||||
public List<String> fragments;
|
||||
public List<JCExpression> expressions;
|
||||
public Type processMethodType;
|
||||
|
||||
protected JCStringTemplate(JCExpression processor,
|
||||
List<String> fragments,
|
||||
|
@ -1480,9 +1480,7 @@ public class Pretty extends JCTree.Visitor {
|
||||
try {
|
||||
JCExpression processor = tree.processor;
|
||||
print("[");
|
||||
if (processor != null) {
|
||||
printExpr(processor);
|
||||
}
|
||||
printExpr(processor);
|
||||
print("]");
|
||||
print("\"" + tree.fragments.stream().collect(Collectors.joining("\\{}")) + "\"");
|
||||
print("(");
|
||||
|
@ -548,11 +548,7 @@ public class TreeInfo {
|
||||
}
|
||||
case STRING_TEMPLATE: {
|
||||
JCStringTemplate node = (JCStringTemplate) tree;
|
||||
if (node.processor == null) {
|
||||
return node.pos;
|
||||
} else {
|
||||
return getStartPos(node.processor);
|
||||
}
|
||||
return node.processor == null ? node.pos : getStartPos(node.processor);
|
||||
}
|
||||
case ERRONEOUS: {
|
||||
JCErroneous node = (JCErroneous)tree;
|
||||
|
@ -22,6 +22,8 @@
|
||||
*/
|
||||
|
||||
// key: compiler.note.preview.filename
|
||||
// key: compiler.err.cant.resolve.location.args
|
||||
// key: compiler.misc.location
|
||||
// key: compiler.note.preview.recompile
|
||||
// key: compiler.err.not.a.processor.type
|
||||
// options: --enable-preview -source ${jdk.version}
|
||||
|
@ -25,7 +25,6 @@
|
||||
// key: compiler.note.preview.recompile
|
||||
// key: compiler.misc.unexpected.ret.val
|
||||
// key: compiler.err.prob.found.req
|
||||
// key: compiler.err.processor.type.cannot.be.a.raw.type
|
||||
// options: --enable-preview -source ${jdk.version}
|
||||
|
||||
import java.lang.*;
|
||||
|
Loading…
Reference in New Issue
Block a user