FIR: hide local types if needed

This commit is contained in:
Jinseong Jeon
2020-08-31 21:55:25 -07:00
committed by Mikhail Glukhikh
parent 9e38e6d051
commit bf918e6184
16 changed files with 93 additions and 48 deletions
@@ -70,14 +70,14 @@ FILE: sealedSupertype.kt
public get(): R|P|
public final val r: R|<anonymous>| = object : R|P| {
public final val r: R|P| = object : R|P| {
private constructor(): R|<anonymous>| {
super<R|P|>()
}
}
public get(): R|<anonymous>|
public get(): R|P|
}
public final class K : R|P| {
@@ -1,5 +1,5 @@
FILE: objectInnerClass.kt
public final val case1: R|<anonymous>| = object : R|A| {
public final val case1: R|A| = object : R|A| {
private constructor(): R|<anonymous>| {
super<R|kotlin/Any|>()
}
@@ -61,13 +61,13 @@ FILE: objectInnerClass.kt
}
public get(): R|<anonymous>|
public get(): R|A|
public final class Case2 : R|kotlin/Any| {
public constructor(): R|Case2| {
super<R|kotlin/Any|>()
}
public final val x: R|<anonymous>| = object : R|Case2.Base| {
public final val x: R|Case2.Base| = object : R|Case2.Base| {
private constructor(): R|<anonymous>| {
this@R|/Case2|.super<R|Case2.Base|>(R|/B.B|())
}
@@ -85,7 +85,7 @@ FILE: objectInnerClass.kt
}
public get(): R|<anonymous>|
public get(): R|Case2.Base|
public final fun R|Case2.Base|.hoo(): R|kotlin/Unit| {
lval x: R|B| = this@R|/Case2.hoo|.R|/Case2.Base.property|
@@ -112,7 +112,7 @@ FILE: objectInnerClass.kt
}
public final fun caseForChild(): R|kotlin/Unit| {
lval child: R|<anonymous>| = this@R|/Case2|.R|/Case2.x|
lval child: R|Case2.Base| = this@R|/Case2|.R|/Case2.x|
R|<local>/child|.R|/Case2.Base.baseFun|()
R|<local>/child|.R|/Case2.Base.property|
(this@R|/Case2|, R|<local>/child|).R|/Case2.hoo|()
@@ -124,7 +124,7 @@ FILE: objectInnerClass.kt
super<R|kotlin/Any|>()
}
public final val x: R|<anonymous>| = object : R|A| {
public final val x: R|A| = object : R|A| {
private constructor(): R|<anonymous>| {
super<R|kotlin/Any|>()
}
@@ -186,7 +186,7 @@ FILE: objectInnerClass.kt
}
public get(): R|<anonymous>|
public get(): R|A|
}
public abstract interface A : R|kotlin/Any| {
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.*
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
import org.jetbrains.kotlin.fir.symbols.constructStarProjectedType
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
@@ -497,8 +498,14 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
val body = result.body
if (result.returnTypeRef is FirImplicitTypeRef) {
val simpleFunction = function as? FirSimpleFunction
if (body != null) {
result.transformReturnTypeRef(transformer, withExpectedType(body.resultType))
result.transformReturnTypeRef(
transformer,
withExpectedType(
body.resultType.hideLocalTypeIfNeeded(simpleFunction?.visibility, simpleFunction?.isInline == true)
)
)
} else {
result.transformReturnTypeRef(
transformer,
@@ -904,7 +911,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
variable.transformReturnTypeRef(
transformer,
withExpectedType(expectedType)
withExpectedType(expectedType.hideLocalTypeIfNeeded((variable as? FirProperty)?.visibility))
)
}
variable.getter != null && variable.getter !is FirDefaultPropertyAccessor -> {
@@ -926,7 +933,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
variable.transformReturnTypeRef(
transformer,
withExpectedType(expectedType)
withExpectedType(expectedType?.hideLocalTypeIfNeeded((variable as? FirProperty)?.visibility))
)
}
else -> {
@@ -949,6 +956,52 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
}
/*
* Suppose a function without an explicit return type just returns an anonymous object:
*
* fun foo(...) = object : ObjectSuperType {
* override fun ...
* }
*
* Without unwrapping, the return type ended up with that anonymous object (<no name provided>), while the resolved super type, which
* acts like an implementing interface, is a better fit. In fact, exposing an anonymous object types is prohibited for certain cases,
* e.g., KT-33917. We can also apply this to any local types.
*/
private fun FirTypeRef.hideLocalTypeIfNeeded(
containingCallableVisibility: Visibility?,
isInlineFunction: Boolean = false
): FirTypeRef {
if (containingCallableVisibility == null) {
return this
}
// Approximate types for non-private (all but package private or private) members.
// Also private inline functions, as per KT-33917.
if (containingCallableVisibility == Visibilities.Public ||
containingCallableVisibility == Visibilities.Protected ||
containingCallableVisibility == Visibilities.Internal ||
(containingCallableVisibility == Visibilities.Private && isInlineFunction)
) {
val firClass =
(((this as? FirResolvedTypeRef)
?.type as? ConeClassLikeType)
?.lookupTag as? ConeClassLookupTagWithFixedSymbol)
?.symbol?.fir
if (firClass?.classId?.isLocal != true) {
return this
}
if (firClass.superTypeRefs.size > 1) {
return buildErrorTypeRef {
diagnostic = ConeSimpleDiagnostic("Cannot hide local type ${firClass.render()}")
}
}
val superType = firClass.superTypeRefs.single()
if (superType is FirResolvedTypeRef && !superType.isAny) {
return superType
}
}
return this
}
private object ImplicitToErrorTypeTransformer : FirTransformer<Nothing?>() {
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return element.compose()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
interface Wrapper { fun runBlock() }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// COMMON_COROUTINES_TEST
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// COMMON_COROUTINES_TEST
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// COMMON_COROUTINES_TEST
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// COMMON_COROUTINES_TEST
// WITH_RUNTIME
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -27,7 +27,7 @@ class Foo {
privateProperty.visible()
protected2Property.<!UNRESOLVED_REFERENCE!>invisible<!>()
public2Property.<!UNRESOLVED_REFERENCE!>invisible<!>()
internalProperty.invisible()
internalProperty.<!UNRESOLVED_REFERENCE!>invisible<!>()
}
@@ -51,7 +51,7 @@ class Foo {
protected2Function().f1()
privateFunction().visible()
internalFunction().invisible()
internalFunction().<!UNRESOLVED_REFERENCE!>invisible<!>()
public2Function().<!UNRESOLVED_REFERENCE!>invisible<!>()
protected2Function().<!UNRESOLVED_REFERENCE!>invisible<!>()
}
@@ -81,7 +81,7 @@ class Foo {
privateProperty.visible()
protected2Property.<!UNRESOLVED_REFERENCE!>invisible<!>()
public2Property.<!UNRESOLVED_REFERENCE!>invisible<!>()
internalProperty.invisible()
internalProperty.<!UNRESOLVED_REFERENCE!>invisible<!>()
}
@@ -105,7 +105,7 @@ class Foo {
protected2Function().f1()
privateFunction().visible()
internalFunction().invisible()
internalFunction().<!UNRESOLVED_REFERENCE!>invisible<!>()
public2Function().<!UNRESOLVED_REFERENCE!>invisible<!>()
protected2Function().<!UNRESOLVED_REFERENCE!>invisible<!>()
}
@@ -137,7 +137,7 @@ fun testProperties() {
packagePublic2Property.f1()
packagePrivateProperty.invisible()
packageInternalProperty.invisible()
packageInternalProperty.<!UNRESOLVED_REFERENCE!>invisible<!>()
packagePublic2Property.<!UNRESOLVED_REFERENCE!>invisible<!>()
}
@@ -160,7 +160,7 @@ fun testFunctions() {
public2Function().f1()
privateFunction().invisible()
internalFunction().invisible()
internalFunction().<!UNRESOLVED_REFERENCE!>invisible<!>()
public2Function().<!UNRESOLVED_REFERENCE!>invisible<!>()
}
@@ -46,7 +46,7 @@ FILE fqName:<root> fileName:/objectLiteralExpressions.kt
RETURN type=kotlin.Nothing from='public final fun <get-test1> (): <root>.test1.<no name provided> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test1 type:<root>.test1.<no name provided> visibility:private [final,static]' type=<root>.test1.<no name provided> origin=null
PROPERTY name:test2 visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:test2 type:<root>.test2.<no name provided> visibility:private [final,static]
FIELD PROPERTY_BACKING_FIELD name:test2 type:<root>.IFoo visibility:private [final,static]
EXPRESSION_BODY
BLOCK type=<root>.test2.<no name provided> origin=OBJECT_LITERAL
CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.IFoo]
@@ -76,11 +76,11 @@ FILE fqName:<root> fileName:/objectLiteralExpressions.kt
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
CONSTRUCTOR_CALL 'private constructor <init> () [primary] declared in <root>.test2.<no name provided>' type=<root>.test2.<no name provided> origin=OBJECT_LITERAL
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test2> visibility:public modality:FINAL <> () returnType:<root>.test2.<no name provided>
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test2> visibility:public modality:FINAL <> () returnType:<root>.IFoo
correspondingProperty: PROPERTY name:test2 visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-test2> (): <root>.test2.<no name provided> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test2 type:<root>.test2.<no name provided> visibility:private [final,static]' type=<root>.test2.<no name provided> origin=null
RETURN type=kotlin.Nothing from='public final fun <get-test2> (): <root>.IFoo declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test2 type:<root>.IFoo visibility:private [final,static]' type=<root>.IFoo origin=null
CLASS CLASS name:Outer modality:FINAL visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Outer
CONSTRUCTOR visibility:public <> () returnType:<root>.Outer [primary]
@@ -111,10 +111,10 @@ FILE fqName:<root> fileName:/objectLiteralExpressions.kt
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:test3 visibility:public modality:FINAL <> ($this:<root>.Outer) returnType:<root>.Outer.test3.<no name provided>
FUN name:test3 visibility:public modality:FINAL <> ($this:<root>.Outer) returnType:<root>.Outer.Inner
$this: VALUE_PARAMETER name:<this> type:<root>.Outer
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test3 (): <root>.Outer.test3.<no name provided> declared in <root>.Outer'
RETURN type=kotlin.Nothing from='public final fun test3 (): <root>.Outer.Inner declared in <root>.Outer'
BLOCK type=<root>.Outer.test3.<no name provided> origin=OBJECT_LITERAL
CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.Outer.Inner]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Outer.test3.<no name provided>
@@ -157,10 +157,10 @@ FILE fqName:<root> fileName:/objectLiteralExpressions.kt
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:test4 visibility:public modality:FINAL <> ($receiver:<root>.Outer) returnType:<root>.test4.<no name provided>
FUN name:test4 visibility:public modality:FINAL <> ($receiver:<root>.Outer) returnType:<root>.Outer.Inner
$receiver: VALUE_PARAMETER name:<this> type:<root>.Outer
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test4 (): <root>.test4.<no name provided> declared in <root>'
RETURN type=kotlin.Nothing from='public final fun test4 (): <root>.Outer.Inner declared in <root>'
BLOCK type=<root>.test4.<no name provided> origin=OBJECT_LITERAL
CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.Outer.Inner]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.test4.<no name provided>
@@ -56,7 +56,7 @@ FILE fqName:<root> fileName:/partialSam.kt
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
PROPERTY name:fsi visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:fsi type:<root>.fsi.<no name provided> visibility:private [final,static]
FIELD PROPERTY_BACKING_FIELD name:fsi type:<root>.Fn<kotlin.String, kotlin.Int> visibility:private [final,static]
EXPRESSION_BODY
BLOCK type=<root>.fsi.<no name provided> origin=OBJECT_LITERAL
CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.Fn<kotlin.String, kotlin.Int>]
@@ -89,13 +89,13 @@ FILE fqName:<root> fileName:/partialSam.kt
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
CONSTRUCTOR_CALL 'private constructor <init> () [primary] declared in <root>.fsi.<no name provided>' type=<root>.fsi.<no name provided> origin=OBJECT_LITERAL
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-fsi> visibility:public modality:FINAL <> () returnType:<root>.fsi.<no name provided>
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-fsi> visibility:public modality:FINAL <> () returnType:<root>.Fn<kotlin.String, kotlin.Int>
correspondingProperty: PROPERTY name:fsi visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-fsi> (): <root>.fsi.<no name provided> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:fsi type:<root>.fsi.<no name provided> visibility:private [final,static]' type=<root>.fsi.<no name provided> origin=null
RETURN type=kotlin.Nothing from='public final fun <get-fsi> (): <root>.Fn<kotlin.String, kotlin.Int> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:fsi type:<root>.Fn<kotlin.String, kotlin.Int> visibility:private [final,static]' type=<root>.Fn<kotlin.String, kotlin.Int> origin=null
PROPERTY name:fis visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:fis type:<root>.fis.<no name provided> visibility:private [final,static]
FIELD PROPERTY_BACKING_FIELD name:fis type:<root>.Fn<kotlin.Int, kotlin.String> visibility:private [final,static]
EXPRESSION_BODY
BLOCK type=<root>.fis.<no name provided> origin=OBJECT_LITERAL
CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.Fn<kotlin.Int, kotlin.String>]
@@ -128,18 +128,18 @@ FILE fqName:<root> fileName:/partialSam.kt
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
CONSTRUCTOR_CALL 'private constructor <init> () [primary] declared in <root>.fis.<no name provided>' type=<root>.fis.<no name provided> origin=OBJECT_LITERAL
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-fis> visibility:public modality:FINAL <> () returnType:<root>.fis.<no name provided>
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-fis> visibility:public modality:FINAL <> () returnType:<root>.Fn<kotlin.Int, kotlin.String>
correspondingProperty: PROPERTY name:fis visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-fis> (): <root>.fis.<no name provided> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:fis type:<root>.fis.<no name provided> visibility:private [final,static]' type=<root>.fis.<no name provided> origin=null
RETURN type=kotlin.Nothing from='public final fun <get-fis> (): <root>.Fn<kotlin.Int, kotlin.String> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:fis type:<root>.Fn<kotlin.Int, kotlin.String> visibility:private [final,static]' type=<root>.Fn<kotlin.Int, kotlin.String> origin=null
FUN name:test visibility:public modality:FINAL <> (j:<root>.J) returnType:kotlin.Unit
VALUE_PARAMETER name:j index:0 type:<root>.J
BLOCK_BODY
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
CALL 'public final fun runConversion (f1: <root>.Fn<kotlin.String, kotlin.Int>, f2: <root>.Fn<kotlin.Int, kotlin.String>): kotlin.Int declared in <root>.J' type=kotlin.Int origin=null
$this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null
f1: CALL 'public final fun <get-fsi> (): <root>.fsi.<no name provided> declared in <root>' type=<root>.fsi.<no name provided> origin=GET_PROPERTY
f1: CALL 'public final fun <get-fsi> (): <root>.Fn<kotlin.String, kotlin.Int> declared in <root>' type=<root>.Fn<kotlin.String, kotlin.Int> origin=GET_PROPERTY
f2: TYPE_OP type=<root>.Fn<kotlin.Int, kotlin.String> origin=SAM_CONVERSION typeOperand=<root>.Fn<kotlin.Int, kotlin.String>
FUN_EXPR type=kotlin.Function3<kotlin.String, kotlin.Int, kotlin.Int, kotlin.String> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (s:kotlin.String, i:kotlin.Int, ti:kotlin.Int) returnType:kotlin.String
@@ -161,4 +161,4 @@ FILE fqName:<root> fileName:/partialSam.kt
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (s: kotlin.String, i: kotlin.Int, ts: kotlin.String): kotlin.Int declared in <root>.test'
CONST Int type=kotlin.Int value=1
f2: CALL 'public final fun <get-fis> (): <root>.fis.<no name provided> declared in <root>' type=<root>.fis.<no name provided> origin=GET_PROPERTY
f2: CALL 'public final fun <get-fis> (): <root>.Fn<kotlin.Int, kotlin.String> declared in <root>' type=<root>.Fn<kotlin.Int, kotlin.String> origin=GET_PROPERTY
@@ -68,11 +68,11 @@ FILE fqName:<root> fileName:/multipleThisReferences.kt
RETURN type=kotlin.Nothing from='public final fun <get-y> (): kotlin.Int declared in <root>.Host'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:y type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null
receiver: GET_VAR '<this>: <root>.Host declared in <root>.Host.<get-y>' type=<root>.Host origin=null
FUN name:test visibility:public modality:FINAL <> ($this:<root>.Host, $receiver:<root>.Outer) returnType:<root>.Host.test.<no name provided>
FUN name:test visibility:public modality:FINAL <> ($this:<root>.Host, $receiver:<root>.Outer) returnType:<root>.Outer.Inner
$this: VALUE_PARAMETER name:<this> type:<root>.Host
$receiver: VALUE_PARAMETER name:<this> type:<root>.Outer
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test (): <root>.Host.test.<no name provided> declared in <root>.Host'
RETURN type=kotlin.Nothing from='public final fun test (): <root>.Outer.Inner declared in <root>.Host'
BLOCK type=<root>.Host.test.<no name provided> origin=OBJECT_LITERAL
CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.Outer.Inner]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Host.test.<no name provided>
@@ -63,10 +63,10 @@ FILE fqName:<root> fileName:/thisOfGenericOuterClass.kt
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:test visibility:public modality:FINAL <> ($receiver:<root>.Outer<kotlin.Int>) returnType:<root>.test.<no name provided>
FUN name:test visibility:public modality:FINAL <> ($receiver:<root>.Outer<kotlin.Int>) returnType:<root>.Outer.Inner<kotlin.Int>
$receiver: VALUE_PARAMETER name:<this> type:<root>.Outer<kotlin.Int>
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test (): <root>.test.<no name provided> declared in <root>'
RETURN type=kotlin.Nothing from='public final fun test (): <root>.Outer.Inner<kotlin.Int> declared in <root>'
BLOCK type=<root>.test.<no name provided> origin=OBJECT_LITERAL
CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.Outer.Inner<kotlin.Int>]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.test.<no name provided>