use of com.oracle.truffle.dsl.processor.java.ElementUtils.typeEquals in project graal by oracle.
the class ExportsParser method parseExports.
private ExportsData parseExports(TypeElement type, List<AnnotationMirror> elementMirrors) {
ExportsData model = new ExportsData(context, type, null);
if (type.getKind().isInterface()) {
model.addError("@%s is not supported for interfaces at the moment.", types.ExportLibrary.asElement().getSimpleName().toString());
return model;
}
if (ElementUtils.getVisibility(type.getModifiers()) == Modifier.PRIVATE) {
model.addError("The exported type must not be private. " + "Increase visibility to resolve this.");
return model;
}
Map<AnnotationMirror, TypeElement> mirrors = new LinkedHashMap<>();
for (AnnotationMirror annotationMirror : elementMirrors) {
mirrors.put(annotationMirror, type);
}
TypeElement superType = type;
while ((superType = getSuperType(superType)) != null) {
for (AnnotationMirror mirror : getRepeatedAnnotation(superType.getAnnotationMirrors(), types.ExportLibrary)) {
mirrors.put(mirror, superType);
}
}
Map<String, List<AnnotationMirror>> mappedMirrors = new LinkedHashMap<>();
for (AnnotationMirror mirror : mirrors.keySet()) {
TypeMirror library = getAnnotationValue(TypeMirror.class, mirror, "value");
mappedMirrors.computeIfAbsent(getTypeId(library), (id) -> new ArrayList<>()).add(mirror);
}
for (Entry<String, List<AnnotationMirror>> entry : mappedMirrors.entrySet()) {
String libraryId = entry.getKey();
List<AnnotationMirror> annotationMirrors = entry.getValue();
AnnotationMirror annotationMirror = annotationMirrors.get(0);
TypeMirror libraryMirror = getAnnotationValue(TypeMirror.class, annotationMirror, "value");
AnnotationValue receiverClassValue = getAnnotationValue(annotationMirror, "receiverType");
boolean explicitReceiver;
TypeMirror receiverClass = getAnnotationValue(TypeMirror.class, annotationMirror, "receiverType", false);
if (receiverClass == null) {
explicitReceiver = false;
receiverClass = type.asType();
} else {
explicitReceiver = true;
}
Map<TypeElement, LibraryData> libraryCache = ProcessorContext.getInstance().getCacheMap(LibraryParser.class);
LibraryData libraryData = libraryCache.computeIfAbsent(fromTypeMirror(libraryMirror), (t) -> new LibraryParser().parse(t));
ExportsLibrary lib = new ExportsLibrary(context, type, annotationMirror, model, libraryData, receiverClass, explicitReceiver);
ExportsLibrary otherLib = model.getExportedLibraries().get(libraryId);
for (AnnotationMirror mirror : annotationMirrors) {
lib.getDeclaringTypes().add(mirrors.get(mirror));
}
model.getExportedLibraries().put(libraryId, lib);
Integer priority = getAnnotationValue(Integer.class, annotationMirror, "priority", false);
if (priority == null && lib.needsDefaultExportProvider()) {
lib.addError(//
"The priority property must be set for default exports based on service providers. " + "See @%s(priority=...) for details.", getSimpleName(types.ExportLibrary));
continue;
} else if (priority != null) {
int prio = priority;
AnnotationValue annotationValue = getAnnotationValue(annotationMirror, "priority");
if (prio < 0) {
LibraryDefaultExportData builtinDefaultExport = libraryData.getBuiltinDefaultExport(receiverClass);
if (builtinDefaultExport != null) {
lib.addError(annotationValue, //
"The provided export receiver type '%s' is not reachable with the given priority. " + //
"The '%s' library specifies @%s(%s) which has receiver type '%s' and that shadows this export. " + "Increase the priority to a positive integer to resolve this.", getSimpleName(receiverClass), getSimpleName(libraryData.getTemplateType()), getSimpleName(types.GenerateLibrary_DefaultExport), getSimpleName(builtinDefaultExport.getImplType()), getSimpleName(builtinDefaultExport.getReceiverType()));
continue;
}
}
if (prio == 0) {
lib.addError(annotationValue, "The set priority must be either positive or negative, but must not be 0.");
continue;
}
lib.setDefaultExportPriority(priority);
}
if (ElementUtils.isPrimitive(receiverClass)) {
lib.addError(annotationMirror, receiverClassValue, "Primitive receiver types are not supported yet.");
continue;
}
if (libraryData == null) {
lib.addError("Class '%s' is not a library annotated with @%s.", getSimpleName(libraryMirror), types.GenerateLibrary.asElement().getSimpleName().toString());
continue;
} else if (libraryData.hasErrors()) {
lib.addError("Library specification %s has errors. Please resolve them first.", getSimpleName(libraryMirror));
continue;
}
if (otherLib != null) {
String message = String.format("Duplicate library specified %s.", getSimpleName(libraryMirror));
otherLib.addError(message);
lib.addError(message);
continue;
}
lib.setUseForAOT(ElementUtils.getAnnotationValue(Boolean.class, annotationMirror, "useForAOT"));
if (libraryData.isGenerateAOT()) {
AnnotationValue useForAOT = getAnnotationValue(annotationMirror, "useForAOT", false);
if (useForAOT == null) {
lib.addError(annotationMirror, useForAOT, //
"The useForAOT property needs to be declared for exports of libraries annotated with @%s. " + "Declare the useForAOT property to resolve this problem.", getSimpleName(types.GenerateAOT));
}
Integer useForAOTPriority = getAnnotationValue(Integer.class, annotationMirror, "useForAOTPriority", false);
if (useForAOTPriority == null && lib.isUseForAOT()) {
lib.addError(//
"The useForAOTPriority property must also be set for libraries used for AOT. " + "See @%s(useForAOTPriority=...) for details.", getSimpleName(types.ExportLibrary));
continue;
} else if (useForAOTPriority != null) {
lib.setUseForAOTPriority(useForAOTPriority);
}
}
if (lib.isUseForAOT() && !lib.isFinalReceiver()) {
AnnotationValue useForAOT = getAnnotationValue(annotationMirror, "useForAOT", false);
lib.addError(annotationMirror, useForAOT, //
"If useForAOT is set to true the receiver type must be a final. " + //
"The compiled code would otherwise cause performance warnings. " + "Add the final modifier to the receiver class or set useForAOT to false to resolve this.");
} else if (lib.isUseForAOT() && lib.isDynamicDispatchTarget()) {
AnnotationMirror dynamicDispatchExportMirror = lib.getReceiverDynamicDispatchExport();
if (dynamicDispatchExportMirror == null) {
throw new AssertionError("Should not reach here. isDynamicDispatchTarget should not return true");
}
if (!ElementUtils.getAnnotationValue(Boolean.class, dynamicDispatchExportMirror, "useForAOT")) {
AnnotationValue useForAOT = getAnnotationValue(annotationMirror, "useForAOT", false);
lib.addError(annotationMirror, useForAOT, "The dynamic dispatch target must set useForAOT to true also for the DynamicDispatch export of the receiver type %s. ", getSimpleName(lib.getReceiverType()));
}
}
if (lib.isUseForAOT() && !libraryData.isGenerateAOT() && !libraryData.isDynamicDispatch()) {
AnnotationValue useForAOT = getAnnotationValue(annotationMirror, "useForAOT", false);
lib.addError(annotationMirror, useForAOT, "The exported library does not support AOT. Add the @%s annotation to the library class %s to resolve this.", getSimpleName(types.GenerateAOT), getQualifiedName(libraryData.getTemplateType()));
}
if (explicitReceiver) {
TypeMirror receiverTypeErasure = context.getEnvironment().getTypeUtils().erasure(libraryData.getSignatureReceiverType());
if (!isSubtype(receiverClass, receiverTypeErasure)) {
lib.addError(annotationMirror, receiverClassValue, "The export receiver type %s is not compatible with the library receiver type '%s' of library '%s'. ", getSimpleName(receiverClass), getSimpleName(libraryData.getSignatureReceiverType()), getSimpleName(libraryData.getTemplateType().asType()));
}
} else {
if (!isSubtype(type.asType(), libraryData.getExportsReceiverType())) {
lib.addError("Type %s is not compatible with the receiver type '%s' of exported library '%s'. " + "Inhert from type '%s' to resolve this.", getSimpleName(type.asType()), getSimpleName(libraryData.getExportsReceiverType()), getSimpleName(libraryData.getTemplateType().asType()), getSimpleName(libraryData.getExportsReceiverType()));
}
}
String transitionLimit = ElementUtils.getAnnotationValue(String.class, annotationMirror, "transitionLimit", false);
if (transitionLimit != null) {
DSLExpressionResolver resolver = new DSLExpressionResolver(context, model.getTemplateType(), NodeParser.importVisibleStaticMembers(model.getTemplateType(), model.getTemplateType(), false));
try {
DSLExpression expression = DSLExpression.parse(transitionLimit);
expression.accept(resolver);
lib.setTransitionLimit(expression);
} catch (InvalidExpressionException e) {
AnnotationValue allowTransition = ElementUtils.getAnnotationValue(annotationMirror, "transitionLimit");
model.addError(annotationMirror, allowTransition, "Error parsing expression '%s': %s", transitionLimit, e.getMessage());
}
}
String delegateTo = ElementUtils.getAnnotationValue(String.class, annotationMirror, "delegateTo", false);
if (delegateTo != null) {
AnnotationValue delegateToValue = ElementUtils.getAnnotationValue(annotationMirror, "delegateTo");
if (receiverClass.getKind() != TypeKind.DECLARED) {
lib.addError(delegateToValue, "The receiver type must be declared type for delegation.");
continue;
}
VariableElement delegateVar = ElementUtils.findVariableElement((DeclaredType) receiverClass, delegateTo);
if (delegateVar == null) {
lib.addError(delegateToValue, "The delegation variable with name '%s' could not be found in type '%s'. " + "Declare a field 'final Object %s' in '%s' to resolve this problem.", delegateTo, ElementUtils.getSimpleName(receiverClass), delegateTo, ElementUtils.getSimpleName(receiverClass));
continue;
}
if (!delegateVar.getModifiers().contains(Modifier.FINAL)) {
lib.addError(delegateToValue, "The delegation variable with name '%s' in type '%s' must be have the modifier final. " + "Make the variable final to resolve the problem.", delegateTo, ElementUtils.getSimpleName(receiverClass));
continue;
}
Element packageElement = ElementUtils.findPackageElement(lib.getTemplateType());
if (!ElementUtils.isVisible(packageElement, delegateVar)) {
lib.addError(delegateToValue, "The delegation variable with name '%s' in type '%s' is not visible in package '%s'. " + "Increase the visibility to resolve this problem.", delegateTo, ElementUtils.getSimpleName(receiverClass), ElementUtils.getPackageName(packageElement));
continue;
}
TypeMirror delegateType = delegateVar.asType();
TypeMirror exportsReceiverType = lib.getLibrary().getSignatureReceiverType();
if (!ElementUtils.isAssignable(delegateType, exportsReceiverType)) {
lib.addError(delegateToValue, "The type of export delegation field '%s' is not assignable to the expected type '%s'. " + "Change the field type to '%s' to resolve this.", ElementUtils.getSimpleName(receiverClass) + "." + delegateTo, ElementUtils.getSimpleName(exportsReceiverType), ElementUtils.getSimpleName(exportsReceiverType));
continue;
}
lib.setDelegationVariable(delegateVar);
}
for (LibraryMessage message : libraryData.getMethods()) {
model.getLibraryMessages().computeIfAbsent(message.getName(), (n) -> new ArrayList<>()).add(message);
}
}
// initialize dynamic dispatch
for (ExportsLibrary exportedLibrary : model.getExportedLibraries().values()) {
if (exportedLibrary.hasErrors()) {
continue;
}
boolean explicitReceiver = exportedLibrary.isExplicitReceiver();
int dynamicDispatchEnabledCount = 0;
for (ExportsLibrary library : model.getExportedLibraries().values()) {
if (library.getLibrary().isDynamicDispatchEnabled()) {
dynamicDispatchEnabledCount++;
}
}
if (exportedLibrary.getLibrary().isDynamicDispatch() && dynamicDispatchEnabledCount > 0) {
exportedLibrary.addError("@%s cannot be used for other libraries if the %s library is exported. " + "Using dynamic dispatch and other libraries is mutually exclusive. " + "To resolve this use the dynamic dispatch mechanism of the receiver type instead to export libraries.", types.ExportLibrary.asElement().getSimpleName().toString(), types.DynamicDispatchLibrary.asElement().getSimpleName().toString());
} else if (explicitReceiver && !exportedLibrary.getLibrary().isDefaultExportLookupEnabled() && !exportedLibrary.isDynamicDispatchTarget() && !exportedLibrary.isBuiltinDefaultExport()) {
String dynamicDispatchDisabled = "";
if (!exportedLibrary.getLibrary().isDynamicDispatchEnabled()) {
dynamicDispatchDisabled = String.format("Note that dynamic dispatch is disabled for the exported library '%s'.%n", ElementUtils.getSimpleName(exportedLibrary.getLibrary().getTemplateType()));
}
//
exportedLibrary.addError(//
exportedLibrary.getTemplateTypeAnnotation(), getAnnotationValue(exportedLibrary.getTemplateTypeAnnotation(), "receiverType"), "Using explicit receiver types is only supported for default exports or types that export %s.%n" + // dynamic dispatch disabled
"%s" + "To resolve this use one of the following strategies:%n" + " - Make the receiver type implicit by applying '@%s(%s.class)' to the receiver type '%s' instead.%n" + " - Declare a default export on the '%s' library with '@%s(%s.class)'%n" + " - Enable default exports with service providers using @%s(defaultExportLookupEnabled=true) on the library and specify an export priority%n" + " - Enable dynamic dispatch by annotating the receiver type with '@%s(%s.class)'.", types.DynamicDispatchLibrary.asElement().getSimpleName().toString(), dynamicDispatchDisabled, types.ExportLibrary.asElement().getSimpleName().toString(), exportedLibrary.getLibrary().getTemplateType().getSimpleName().toString(), ElementUtils.getSimpleName(exportedLibrary.getExplicitReceiver()), exportedLibrary.getLibrary().getTemplateType().getSimpleName().toString(), types.GenerateLibrary_DefaultExport.asElement().getSimpleName().toString(), ElementUtils.getSimpleName(exportedLibrary.getTemplateType().asType()), ElementUtils.getSimpleName(types.GenerateLibrary), types.ExportLibrary.asElement().getSimpleName().toString(), types.DynamicDispatchLibrary.asElement().getSimpleName().toString());
} else {
if (explicitReceiver && !exportedLibrary.isBuiltinDefaultExport()) {
boolean foundInvalidExportsOnReceiver = false;
superType = ElementUtils.castTypeElement(exportedLibrary.getExplicitReceiver());
while (superType != null) {
List<AnnotationMirror> exports = getRepeatedAnnotation(superType.getAnnotationMirrors(), types.ExportLibrary);
for (AnnotationMirror export : exports) {
TypeMirror exportedLibraryType = getAnnotationValue(TypeMirror.class, export, "value");
if (!ElementUtils.typeEquals(exportedLibraryType, types.DynamicDispatchLibrary)) {
foundInvalidExportsOnReceiver = true;
break;
}
}
superType = getSuperType(superType);
}
if (foundInvalidExportsOnReceiver) {
AnnotationValue receiverClassValue = getAnnotationValue(exportedLibrary.getMessageAnnotation(), "receiverType");
exportedLibrary.addError(exportedLibrary.getMessageAnnotation(), receiverClassValue, "An export that is used for dynamic dispatch must not export any libraries other than %s with the receiver type.", types.DynamicDispatchLibrary.asElement().getSimpleName().toString());
continue;
}
}
}
}
return model;
}
Aggregations