anchor.diff:          final propertyHir = getPropertyDeclarationHir(context, id);
           if (propertyAst.type == null) {
             final range = propertyAst.name.span.toRange(server, resourceId);
  -          labels.add(TypeLabel(range, propertyHir.type.toString()));
  +          labels.add(TypeLabel(range, _typeToString(propertyHir.type)));
           }
   
           if (propertyAst.initializer != null) {
  
positive.code:         if (functionAst.returnType == null) {
            final range =
                functionAst.rightParenthesis.span.toRange(server, resourceId);
            labels.add(TypeLabel(range, functionHir.returnType.toString()));
          }
  
          if (functionAst.body != null) handleBody(functionAst.body);
  
negative.code:     return labels;
    },
  );
  
  String _typeToString(CandyType type) {
    String mapAndJoin(List<CandyType> types) =>
        types.map(_typeToString).join(', ');
  
    return type.maybeMap(
      user: (it) {
        if (it.arguments.isEmpty) return it.name;
        return '${it.name}<${mapAndJoin(it.arguments)}>';
      },
      this_: (_) => 'This',
      tuple: (it) => '(${mapAndJoin(it.items)})',
      function: (it) {
        final receiver =
            it.receiverType == null ? '' : '${_typeToString(it.receiverType)}.';
        return '$receiver(${mapAndJoin(it.parameterTypes)}) => ${it.returnType}';
      },
      union: (it) => it.types.map(_typeToString).join(' | '),
      intersection: (it) => it.types.map(_typeToString).join(' & '),
      orElse: () => type.toString(),
    );
  }
  
  class _BodyPropertyVisitor extends ast.TraversingAstVisitor {
    _BodyPropertyVisitor._(
  