TypeName cataMapperTypeName(DataConstructor dc) { TypeName[] argsTypeNames = concat( dc.arguments().stream().map(DataArgument::type), dc.typeRestrictions() .stream() .map(TypeRestriction::idFunction) .map(DataArgument::type)) .map(t -> Utils.asBoxedType.visit(t, utils.types())) .map(this::substituteTypeWithRecursionVar) .map(TypeName::get) .toArray(TypeName[]::new); return adt.dataConstruction().isVisitorDispatch() ? argsTypeNames.length == 0 ? ParameterizedTypeName.get( ClassName.get(FlavourImpl.findF0(context.flavour(), utils.elements())), TypeName.get(adt.matchMethod().returnTypeVariable())) : argsTypeNames.length == 1 ? ParameterizedTypeName.get( ClassName.get(FlavourImpl.findF(context.flavour(), utils.elements())), argsTypeNames[0], TypeName.get(adt.matchMethod().returnTypeVariable())) : ParameterizedTypeName.get( Utils.getClassName(context, MapperDerivator.mapperInterfaceName(dc)), concat( concat( dc.typeVariables().stream().map(TypeVariableName::get), fold( MapperDerivator.findInductiveArgument(utils, adt, dc), Stream.<TypeName>of(), tm -> Stream.of( ParameterizedTypeName.get( ClassName.get( FlavourImpl.findF0( context.flavour(), utils.elements())), TypeName.get( adt.matchMethod().returnTypeVariable()))))), Stream.of(TypeVariableName.get(adt.matchMethod().returnTypeVariable()))) .toArray(TypeName[]::new)) : TypeName.get( utils .types() .getDeclaredType( Utils.asTypeElement.visit(dc.deconstructor().visitorType().asElement()).get(), dc.deconstructor() .visitorType() .getTypeArguments() .stream() .map(this::substituteTypeWithRecursionVar) .toArray(TypeMirror[]::new))); }
private DeriveResult<DerivedCodeSpec> functionDispatchImpl(List<DataConstructor> constructors) { NameAllocator nameAllocator = nameAllocator(constructors); TypeElement f = FlavourImpl.findF(context.flavour(), utils.elements()); TypeName returnType = TypeName.get( utils .types() .getDeclaredType( f, adt.typeConstructor().declaredType(), adt.matchMethod().returnTypeVariable())); TypeSpec wrapper = TypeSpec.anonymousClassBuilder("") .addField( FieldSpec.builder(returnType, nameAllocator.get("cata")) .initializer( CodeBlock.builder() .addStatement( "$L -> $L.$L($L)", nameAllocator.get("adt var"), nameAllocator.get("adt var"), adt.matchMethod().element().getSimpleName(), Utils.joinStringsAsArguments( constructors .stream() .map( constructor -> constructor .arguments() .stream() .map(DataArguments::getType) .noneMatch( tm -> utils .types() .isSameType( tm, adt.typeConstructor() .declaredType())) ? constructor.name() : CodeBlock.builder() .add( "($L) -> $L.$L($L)", Utils.asLambdaParametersString( constructor.arguments(), constructor.typeRestrictions()), constructor.name(), MapperDerivator.mapperApplyMethod( utils, context, constructor), Utils.joinStringsAsArguments( Stream.concat( constructor .arguments() .stream() .map( argument -> utils .types() .isSameType( argument .type(), adt.typeConstructor() .declaredType()) ? "() -> this." + nameAllocator .get( "cata") + "." + FlavourImpl .functionApplyMethod( utils, context) + "(" + argument .fieldName() + ")" : argument .fieldName()), constructor .typeRestrictions() .stream() .map( TypeRestriction ::idFunction) .map( DataArgument ::fieldName)))) .build() .toString()))) .build()) .build()) .build(); MethodSpec cataMethod = MethodSpec.methodBuilder("cata") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .addTypeVariables( Stream.concat( adt.typeConstructor().typeVariables().stream(), Stream.of(adt.matchMethod().returnTypeVariable())) .map(TypeVariableName::get) .collect(Collectors.toList())) .returns(returnType) .addParameters( constructors .stream() .map( dc -> ParameterSpec.builder( cataMapperTypeName(dc), MapperDerivator.mapperFieldName(dc)) .build()) .collect(toList())) .addStatement("return $L.$L", wrapper, nameAllocator.get("cata")) .build(); return result(methodSpec(cataMethod)); }