Annotated the return type of 'elvis' function with @Exact
fun <T> ELVIS(T?, T): @Exact T
This commit is contained in:
+1
@@ -127,6 +127,7 @@ public class AnnotationSplitter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isEmpty() = annotations.isEmpty()
|
override fun isEmpty() = annotations.isEmpty()
|
||||||
|
override fun hasAnnotation(fqName: FqName) = annotations.hasAnnotation(fqName)
|
||||||
override fun findAnnotation(fqName: FqName) = annotations.findAnnotation(fqName)
|
override fun findAnnotation(fqName: FqName) = annotations.findAnnotation(fqName)
|
||||||
override fun getUseSiteTargetedAnnotations() = annotations.getUseSiteTargetedAnnotations()
|
override fun getUseSiteTargetedAnnotations() = annotations.getUseSiteTargetedAnnotations()
|
||||||
override fun getAllAnnotations() = annotations.getAllAnnotations()
|
override fun getAllAnnotations() = annotations.getAllAnnotations()
|
||||||
|
|||||||
+3
-2
@@ -63,6 +63,7 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt;
|
import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt;
|
||||||
import org.jetbrains.kotlin.types.*;
|
import org.jetbrains.kotlin.types.*;
|
||||||
|
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ResolveConstruct;
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
||||||
import org.jetbrains.kotlin.types.expressions.unqualifiedSuper.UnqualifiedSuperKt;
|
import org.jetbrains.kotlin.types.expressions.unqualifiedSuper.UnqualifiedSuperKt;
|
||||||
@@ -830,7 +831,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
// See also CallExpressionResolver.getSimpleNameExpressionTypeInfo, .getQualifiedExpressionTypeInfo
|
// See also CallExpressionResolver.getSimpleNameExpressionTypeInfo, .getQualifiedExpressionTypeInfo
|
||||||
Call call = createCallForSpecialConstruction(expression, expression.getOperationReference(), Collections.singletonList(baseExpression));
|
Call call = createCallForSpecialConstruction(expression, expression.getOperationReference(), Collections.singletonList(baseExpression));
|
||||||
components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
|
components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
|
||||||
call, "ExclExcl", Collections.singletonList("baseExpr"), Collections.singletonList(true), context, null);
|
call, ResolveConstruct.EXCL_EXCL, Collections.singletonList("baseExpr"), Collections.singletonList(true), context, null);
|
||||||
JetTypeInfo baseTypeInfo = BindingContextUtils.getRecordedTypeInfo(baseExpression, context.trace.getBindingContext());
|
JetTypeInfo baseTypeInfo = BindingContextUtils.getRecordedTypeInfo(baseExpression, context.trace.getBindingContext());
|
||||||
|
|
||||||
if (ArgumentTypeResolver.isFunctionLiteralArgument(baseExpression, context)) {
|
if (ArgumentTypeResolver.isFunctionLiteralArgument(baseExpression, context)) {
|
||||||
@@ -1163,7 +1164,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
Call call = createCallForSpecialConstruction(expression, expression.getOperationReference(), Lists.newArrayList(left, right));
|
Call call = createCallForSpecialConstruction(expression, expression.getOperationReference(), Lists.newArrayList(left, right));
|
||||||
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
|
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
|
||||||
call, "Elvis", Lists.newArrayList("left", "right"), Lists.newArrayList(true, false), contextWithExpectedType, null);
|
call, ResolveConstruct.ELVIS, Lists.newArrayList("left", "right"), Lists.newArrayList(true, false), contextWithExpectedType, null);
|
||||||
JetTypeInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext());
|
JetTypeInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext());
|
||||||
if (ArgumentTypeResolver.isFunctionLiteralArgument(left, context)) {
|
if (ArgumentTypeResolver.isFunctionLiteralArgument(left, context)) {
|
||||||
context.trace.report(USELESS_ELVIS_ON_FUNCTION_LITERAL.on(expression.getOperationReference()));
|
context.trace.report(USELESS_ELVIS_ON_FUNCTION_LITERAL.on(expression.getOperationReference()));
|
||||||
|
|||||||
+23
-5
@@ -47,10 +47,12 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
|
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.AnnotationsForResolveKt;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
import org.jetbrains.kotlin.types.TypeUtils;
|
import org.jetbrains.kotlin.types.TypeUtils;
|
||||||
import org.jetbrains.kotlin.types.Variance;
|
import org.jetbrains.kotlin.types.Variance;
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -61,6 +63,20 @@ import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.Co
|
|||||||
public class ControlStructureTypingUtils {
|
public class ControlStructureTypingUtils {
|
||||||
private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class);
|
private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class);
|
||||||
|
|
||||||
|
public enum ResolveConstruct {
|
||||||
|
IF("if"), ELVIS("elvis"), EXCL_EXCL("ExclExcl");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
ResolveConstruct(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final CallResolver callResolver;
|
private final CallResolver callResolver;
|
||||||
private final DataFlowAnalyzer dataFlowAnalyzer;
|
private final DataFlowAnalyzer dataFlowAnalyzer;
|
||||||
private final ModuleDescriptor moduleDescriptor;
|
private final ModuleDescriptor moduleDescriptor;
|
||||||
@@ -77,15 +93,15 @@ public class ControlStructureTypingUtils {
|
|||||||
|
|
||||||
/*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
|
/*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
|
||||||
@NotNull Call call,
|
@NotNull Call call,
|
||||||
@NotNull String constructionName,
|
@NotNull ResolveConstruct construct,
|
||||||
@NotNull List<String> argumentNames,
|
@NotNull List<String> argumentNames,
|
||||||
@NotNull List<Boolean> isArgumentNullable,
|
@NotNull List<Boolean> isArgumentNullable,
|
||||||
@NotNull ExpressionTypingContext context,
|
@NotNull ExpressionTypingContext context,
|
||||||
@Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
|
@Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
|
||||||
) {
|
) {
|
||||||
SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
|
SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
|
||||||
constructionName.toUpperCase(), argumentNames, isArgumentNullable);
|
construct, argumentNames, isArgumentNullable);
|
||||||
TracingStrategy tracing = createTracingForSpecialConstruction(call, constructionName, context);
|
TracingStrategy tracing = createTracingForSpecialConstruction(call, construct.getName(), context);
|
||||||
ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function);
|
ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function);
|
||||||
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
|
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
|
||||||
call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
|
call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
|
||||||
@@ -94,12 +110,13 @@ public class ControlStructureTypingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SimpleFunctionDescriptorImpl createFunctionDescriptorForSpecialConstruction(
|
private SimpleFunctionDescriptorImpl createFunctionDescriptorForSpecialConstruction(
|
||||||
@NotNull String constructionName,
|
@NotNull ResolveConstruct construct,
|
||||||
@NotNull List<String> argumentNames,
|
@NotNull List<String> argumentNames,
|
||||||
@NotNull List<Boolean> isArgumentNullable
|
@NotNull List<Boolean> isArgumentNullable
|
||||||
) {
|
) {
|
||||||
assert argumentNames.size() == isArgumentNullable.size();
|
assert argumentNames.size() == isArgumentNullable.size();
|
||||||
|
|
||||||
|
String constructionName = construct.getName().toUpperCase();
|
||||||
Name specialFunctionName = Name.identifier("<SPECIAL-FUNCTION-FOR-" + constructionName + "-RESOLVE>");
|
Name specialFunctionName = Name.identifier("<SPECIAL-FUNCTION-FOR-" + constructionName + "-RESOLVE>");
|
||||||
|
|
||||||
SimpleFunctionDescriptorImpl function = SimpleFunctionDescriptorImpl.create(
|
SimpleFunctionDescriptorImpl function = SimpleFunctionDescriptorImpl.create(
|
||||||
@@ -126,12 +143,13 @@ public class ControlStructureTypingUtils {
|
|||||||
);
|
);
|
||||||
valueParameters.add(valueParameter);
|
valueParameters.add(valueParameter);
|
||||||
}
|
}
|
||||||
|
KotlinType returnType = construct != ResolveConstruct.ELVIS ? type : TypeUtilsKt.replaceAnnotations(type, AnnotationsForResolveKt.getExactInAnnotations());
|
||||||
function.initialize(
|
function.initialize(
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
Lists.newArrayList(typeParameter),
|
Lists.newArrayList(typeParameter),
|
||||||
valueParameters,
|
valueParameters,
|
||||||
type,
|
returnType,
|
||||||
Modality.FINAL,
|
Modality.FINAL,
|
||||||
Visibilities.PUBLIC
|
Visibilities.PUBLIC
|
||||||
);
|
);
|
||||||
|
|||||||
+2
-1
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.types.CommonSupertypes;
|
|||||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
import org.jetbrains.kotlin.types.TypeUtils;
|
import org.jetbrains.kotlin.types.TypeUtils;
|
||||||
|
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ResolveConstruct;
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
MutableDataFlowInfoForArguments dataFlowInfoForArguments =
|
MutableDataFlowInfoForArguments dataFlowInfoForArguments =
|
||||||
createDataFlowInfoForArgumentsForIfCall(callForIf, thenInfo, elseInfo);
|
createDataFlowInfoForArgumentsForIfCall(callForIf, thenInfo, elseInfo);
|
||||||
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
|
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
|
||||||
callForIf, "If", Lists.newArrayList("thenBranch", "elseBranch"),
|
callForIf, ResolveConstruct.IF, Lists.newArrayList("thenBranch", "elseBranch"),
|
||||||
Lists.newArrayList(false, false),
|
Lists.newArrayList(false, false),
|
||||||
contextWithExpectedType, dataFlowInfoForArguments);
|
contextWithExpectedType, dataFlowInfoForArguments);
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -8,8 +8,8 @@ fun test() {
|
|||||||
|
|
||||||
// KT-KT-9070
|
// KT-KT-9070
|
||||||
<!TYPE_MISMATCH!>{ }<!> <!USELESS_ELVIS!><!USELESS_ELVIS_ON_FUNCTION_LITERAL!>?:<!> 1<!>
|
<!TYPE_MISMATCH!>{ }<!> <!USELESS_ELVIS!><!USELESS_ELVIS_ON_FUNCTION_LITERAL!>?:<!> 1<!>
|
||||||
use(<!TYPE_MISMATCH!>{ 2 }<!> <!USELESS_ELVIS_ON_FUNCTION_LITERAL!>?:<!> 1);
|
use({ 2 } <!USELESS_ELVIS_ON_FUNCTION_LITERAL!>?:<!> 1);
|
||||||
|
|
||||||
1 <!USELESS_ELVIS!>?: <!TYPE_MISMATCH, UNUSED_FUNCTION_LITERAL!>{ }<!><!>
|
1 <!USELESS_ELVIS!>?: <!TYPE_MISMATCH, UNUSED_FUNCTION_LITERAL!>{ }<!><!>
|
||||||
use(1 <!USELESS_ELVIS!>?: <!TYPE_MISMATCH!>{ }<!><!>)
|
use(1 <!USELESS_ELVIS!>?: { }<!>)
|
||||||
}
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||||
|
// !CHECK_TYPE
|
||||||
|
|
||||||
|
fun <T: Any> foo(f: (T) -> Unit): T? = null // T is used only as return type
|
||||||
|
fun test() {
|
||||||
|
val x = foo { it checkType { _<String>() }} ?: "" // foo() is inferred as foo<String>, which isn't very good
|
||||||
|
val y: Any = foo { it checkType { _<Any>() } } ?: "" // but for now it's fixed by specifying expected type
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun </*0*/ T : kotlin.Any> foo(/*0*/ f: (T) -> kotlin.Unit): T?
|
||||||
|
public fun test(): kotlin.Unit
|
||||||
@@ -13088,6 +13088,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inferenceForElvis.kt")
|
||||||
|
public void testInferenceForElvis() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/specialConstructions/inferenceForElvis.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("multipleSuperClasses.kt")
|
@TestMetadata("multipleSuperClasses.kt")
|
||||||
public void testMultipleSuperClasses() throws Exception {
|
public void testMultipleSuperClasses() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/specialConstructions/multipleSuperClasses.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/specialConstructions/multipleSuperClasses.kt");
|
||||||
|
|||||||
@@ -80,6 +80,11 @@ class FilteredAnnotations(
|
|||||||
private val delegate: Annotations,
|
private val delegate: Annotations,
|
||||||
private val fqNameFilter: (FqName) -> Boolean
|
private val fqNameFilter: (FqName) -> Boolean
|
||||||
) : Annotations {
|
) : Annotations {
|
||||||
|
|
||||||
|
override fun hasAnnotation(fqName: FqName) =
|
||||||
|
if (fqNameFilter(fqName)) delegate.hasAnnotation(fqName)
|
||||||
|
else false
|
||||||
|
|
||||||
override fun findAnnotation(fqName: FqName) =
|
override fun findAnnotation(fqName: FqName) =
|
||||||
if (fqNameFilter(fqName)) delegate.findAnnotation(fqName)
|
if (fqNameFilter(fqName)) delegate.findAnnotation(fqName)
|
||||||
else null
|
else null
|
||||||
@@ -115,6 +120,8 @@ class CompositeAnnotations(
|
|||||||
|
|
||||||
override fun isEmpty() = delegates.all { it.isEmpty() }
|
override fun isEmpty() = delegates.all { it.isEmpty() }
|
||||||
|
|
||||||
|
override fun hasAnnotation(fqName: FqName) = delegates.asSequence().any { it.hasAnnotation(fqName) }
|
||||||
|
|
||||||
override fun findAnnotation(fqName: FqName) = delegates.asSequence().map { it.findAnnotation(fqName) }.filterNotNull().firstOrNull()
|
override fun findAnnotation(fqName: FqName) = delegates.asSequence().map { it.findAnnotation(fqName) }.filterNotNull().firstOrNull()
|
||||||
|
|
||||||
override fun findExternalAnnotation(fqName: FqName) = delegates.asSequence().map { it.findExternalAnnotation(fqName) }.filterNotNull().firstOrNull()
|
override fun findExternalAnnotation(fqName: FqName) = delegates.asSequence().map { it.findExternalAnnotation(fqName) }.filterNotNull().firstOrNull()
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.resolve.descriptorUtil
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -41,3 +43,21 @@ public fun CallableDescriptor.hasLowPriorityInOverloadResolution(): Boolean = an
|
|||||||
private val ONLY_INPUT_TYPES_FQ_NAME = FqName("kotlin.internal.OnlyInputTypes")
|
private val ONLY_INPUT_TYPES_FQ_NAME = FqName("kotlin.internal.OnlyInputTypes")
|
||||||
|
|
||||||
public fun TypeParameterDescriptor.hasOnlyInputTypesAnnotation(): Boolean = annotations.hasAnnotation(ONLY_INPUT_TYPES_FQ_NAME)
|
public fun TypeParameterDescriptor.hasOnlyInputTypesAnnotation(): Boolean = annotations.hasAnnotation(ONLY_INPUT_TYPES_FQ_NAME)
|
||||||
|
|
||||||
|
public fun getExactInAnnotations(): Annotations = AnnotationsWithOnly(EXACT_ANNOTATION_FQ_NAME)
|
||||||
|
|
||||||
|
private class AnnotationsWithOnly(val presentAnnotation: FqName): Annotations {
|
||||||
|
override fun iterator(): Iterator<AnnotationDescriptor> = listOf<AnnotationDescriptor>().iterator()
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean = false
|
||||||
|
|
||||||
|
override fun hasAnnotation(fqName: FqName): Boolean = fqName == this.presentAnnotation
|
||||||
|
|
||||||
|
override fun findAnnotation(fqName: FqName): AnnotationDescriptor? = null
|
||||||
|
|
||||||
|
override fun findExternalAnnotation(fqName: FqName): AnnotationDescriptor? = null
|
||||||
|
|
||||||
|
override fun getUseSiteTargetedAnnotations(): List<AnnotationWithTarget> = emptyList()
|
||||||
|
|
||||||
|
override fun getAllAnnotations(): List<AnnotationWithTarget> = emptyList()
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ fun stringLen(s : String?) : Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun stringReturnInLeftLen(s : String?) : Int {
|
fun stringReturnInLeftLen(s : String?) : Int {
|
||||||
val s1 : String = (if (s != null) { return s.length() } else { null }) ?: return 0
|
val s1 = (if (s != null) { return s.length() } else { null }) ?: return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
Reference in New Issue
Block a user