NI: do type checking for anonymous functions not inside a call
^KT-38890 Fixed ^KT-38439 Fixed
This commit is contained in:
+5
@@ -8195,6 +8195,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/lambdaInLambda2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("missedTypeMismatch.kt")
|
||||
public void testMissedTypeMismatch() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt")
|
||||
public void testPrematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt");
|
||||
|
||||
+30
-9
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.checkers.TrailingCommaChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.TrailingCommaDeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope
|
||||
@@ -116,17 +115,35 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
|
||||
return if (isDeclaration) {
|
||||
createTypeInfo(components.dataFlowAnalyzer.checkStatementType(function, context), context)
|
||||
} else {
|
||||
val expectedType = context.expectedType
|
||||
|
||||
val functionalTypeExpected = expectedType.isBuiltinFunctionalType()
|
||||
val newInferenceEnabled = components.languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
|
||||
|
||||
// We forbid anonymous function expressions to suspend type coercion for now, until `suspend fun` syntax is supported
|
||||
val resultType = functionDescriptor.createFunctionType(components.builtIns, suspendFunction = false)
|
||||
val resultType = functionDescriptor.createFunctionType(
|
||||
components.builtIns,
|
||||
suspendFunction = false
|
||||
)
|
||||
|
||||
if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) && functionalTypeExpected && !expectedType.isSuspendFunctionType)
|
||||
if (newInferenceEnabled) {
|
||||
// We should avoid type checking for types containing `NO_EXPECTED_TYPE`, the error will be report later if needed
|
||||
if (!context.expectedType.contains { it === NO_EXPECTED_TYPE }) {
|
||||
/*
|
||||
* We do type checking without converted vararg type as the new inference create expected type with raw vararg type (see KotlinResolutionCallbacksImpl.kt)
|
||||
* Example:
|
||||
* fun foo(x: Any?) {}
|
||||
* val x = foo(fun(vararg p: Int) {})
|
||||
* In NI, context.expectedType = `Function1<Int, Unit>`
|
||||
*/
|
||||
val typeToTypeCheck = functionDescriptor.createFunctionType(
|
||||
components.builtIns,
|
||||
suspendFunction = false,
|
||||
shouldUseVarargType = true
|
||||
)
|
||||
components.dataFlowAnalyzer.checkType(typeToTypeCheck, function, context)
|
||||
}
|
||||
createTypeInfo(resultType, context)
|
||||
else
|
||||
} else {
|
||||
components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, function)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,12 +387,16 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
|
||||
}
|
||||
}
|
||||
|
||||
fun SimpleFunctionDescriptor.createFunctionType(builtIns: KotlinBuiltIns, suspendFunction: Boolean = false): KotlinType? {
|
||||
fun SimpleFunctionDescriptor.createFunctionType(
|
||||
builtIns: KotlinBuiltIns,
|
||||
suspendFunction: Boolean = false,
|
||||
shouldUseVarargType: Boolean = false
|
||||
): KotlinType? {
|
||||
return createFunctionType(
|
||||
builtIns,
|
||||
Annotations.EMPTY,
|
||||
extensionReceiverParameter?.type,
|
||||
valueParameters.map { it.type },
|
||||
if (shouldUseVarargType) valueParameters.map { it.varargElementType ?: it.type } else valueParameters.map { it.type },
|
||||
null,
|
||||
returnType ?: return null,
|
||||
suspendFunction = suspendFunction
|
||||
|
||||
@@ -9,7 +9,7 @@ fun testReturnType(foo: String) {
|
||||
|
||||
val bas: () -> String = fun () = foo
|
||||
|
||||
val bag: () -> Int = <!OI;TYPE_MISMATCH!>fun () = foo<!>
|
||||
val bag: () -> Int = <!TYPE_MISMATCH!>fun () = foo<!>
|
||||
}
|
||||
|
||||
fun testParamType() {
|
||||
@@ -18,7 +18,7 @@ fun testParamType() {
|
||||
bar.checkType { _<(String) -> Unit>() }
|
||||
|
||||
val bas: (String) -> Unit = fun (param: String) {}
|
||||
val bag: (Int) -> Unit = <!OI;TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>param: String<!>) {}<!>
|
||||
val bag: (Int) -> Unit = <!TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>param: String<!>) {}<!>
|
||||
}
|
||||
|
||||
fun testReceiverType() {
|
||||
@@ -28,5 +28,5 @@ fun testReceiverType() {
|
||||
|
||||
val bas: String.() -> Unit = fun String.() {}
|
||||
|
||||
val bag: Int.() -> Unit = <!OI;TYPE_MISMATCH!>fun String.() {}<!>
|
||||
val bag: Int.() -> Unit = <!TYPE_MISMATCH!>fun String.() {}<!>
|
||||
}
|
||||
+1
-1
@@ -17,4 +17,4 @@ fun test2(a: () -> List<Int>) {
|
||||
|
||||
val a: (Int) -> Unit = fun(x) { checkSubtype<Int>(x) }
|
||||
|
||||
val b: (Int) -> Unit = <!OI;TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>
|
||||
val b: (Int) -> Unit = <!TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>
|
||||
+6
-6
@@ -6,22 +6,22 @@ val a = fun (<!CANNOT_INFER_PARAMETER_TYPE!>x<!>) = <!DEBUG_INFO_ELEMENT_WITH_ER
|
||||
|
||||
val b: (Int) -> Int = fun (x) = x + 3
|
||||
|
||||
val c: (Int, String) -> Int = <!OI;TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(x)<!> = 3<!>
|
||||
val c: (Int, String) -> Int = <!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(x)<!> = 3<!>
|
||||
|
||||
val d: (Int, String) -> Int = <!OI;TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(x)<!> = 3<!>
|
||||
val d: (Int, String) -> Int = <!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(x)<!> = 3<!>
|
||||
|
||||
val e: (Int, String) -> Int = <!OI;TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> = 3<!>
|
||||
val e: (Int, String) -> Int = <!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> = 3<!>
|
||||
|
||||
val f: (Int) -> Int = <!OI;TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) = 3<!>
|
||||
val f: (Int) -> Int = <!TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) = 3<!>
|
||||
|
||||
fun test1(a: (Int) -> Unit) {
|
||||
test1(fun (x) { checkSubtype<Int>(x)})
|
||||
}
|
||||
|
||||
fun test2(a: (Int) -> Unit) {
|
||||
test2(<!TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>)
|
||||
test2(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>)
|
||||
}
|
||||
|
||||
fun test3(a: (Int, String) -> Unit) {
|
||||
test3(<!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> {}<!>)
|
||||
test3(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> {}<!>)
|
||||
}
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
fun foo(<!UNUSED_PARAMETER!>f<!>: String.() -> Int) {}
|
||||
val test = foo(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun <!NI;EXPECTED_PARAMETERS_NUMBER_MISMATCH!>()<!> = <!UNRESOLVED_REFERENCE!>length<!><!>)
|
||||
val test = foo(<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun <!NI;EXPECTED_PARAMETERS_NUMBER_MISMATCH!>()<!> = <!UNRESOLVED_REFERENCE!>length<!><!>)
|
||||
Vendored
+1
-1
@@ -16,6 +16,6 @@ fun test(s: Sub) {
|
||||
t: Trait -> s
|
||||
}
|
||||
|
||||
foo(<!TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>t: Sub<!>) = s<!>)
|
||||
foo(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>t: Sub<!>) = s<!>)
|
||||
foo(<!TYPE_MISMATCH!>fun(t): Super = s<!>)
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNCHECKED_CAST
|
||||
// Issues: KT-38890, KT-38439
|
||||
|
||||
fun foo(x: () -> Int) {}
|
||||
|
||||
fun <T>id(x: T) = x
|
||||
|
||||
// Before the fix, there wasn't any type mismatch error in NI due to result type not being a subtype of expected type
|
||||
fun main() {
|
||||
val x: () -> Int = { "" }
|
||||
|
||||
val a0: () -> Int = fun(): String = "1"
|
||||
val a1: () -> Int = (fun() = "1")
|
||||
val a2: () -> Unit = (fun() = "1")
|
||||
val a3: Unit = (fun() = "1")
|
||||
val a4 = (fun() = "1")
|
||||
val a5 = (fun(): String = "1")
|
||||
val a6: () -> Int = (fun() = 1)
|
||||
val a7: () -> Int = (fun(): String = "1") as () -> Int
|
||||
val a8: () -> Int = fun(): String = "1"
|
||||
val a9: () -> () -> () -> Int = fun(): () -> () -> String = fun(): () -> String = fun(): String = "1"
|
||||
|
||||
<!INAPPLICABLE_CANDIDATE!>foo<!>(fun(): String = "1")
|
||||
<!INAPPLICABLE_CANDIDATE!>foo<!>(((fun(): String = "1")))
|
||||
|
||||
val a10: Int.(String) -> Int = fun (x: String) = 10
|
||||
val a11: () -> () -> () -> Int = fun() = fun() = fun(): String = "1"
|
||||
|
||||
val a12: Int = fun(): String = "1"
|
||||
val a13: Int = fun() = fun(): String = "1"
|
||||
val a14: Int = fun() = fun() = "1"
|
||||
val a15: Int = fun() = fun() = {}
|
||||
val a16: Int = fun() = fun() {}
|
||||
|
||||
val a17: () -> Unit = fun() {}
|
||||
val a18: () -> Int = fun() {}
|
||||
val a19: () -> () -> Int = fun() = fun() {}
|
||||
val a20: () -> () -> () -> Unit = fun() = fun() = {}
|
||||
val a21: () -> () -> () -> Int = fun() = fun() = {}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNCHECKED_CAST
|
||||
// Issues: KT-38890, KT-38439
|
||||
|
||||
fun foo(x: () -> Int) {}
|
||||
|
||||
fun <T>id(x: T) = x
|
||||
|
||||
// Before the fix, there wasn't any type mismatch error in NI due to result type not being a subtype of expected type
|
||||
fun main() {
|
||||
val x: () -> Int = { <!TYPE_MISMATCH!>""<!> }
|
||||
|
||||
val a0: () -> Int = <!TYPE_MISMATCH!>fun(): String = "1"<!>
|
||||
val a1: () -> Int = (<!TYPE_MISMATCH!>fun() = "1"<!>)
|
||||
val a2: () -> Unit = (<!TYPE_MISMATCH!>fun() = "1"<!>)
|
||||
val a3: Unit = (<!TYPE_MISMATCH!>fun() = "1"<!>)
|
||||
val a4 = (fun() = "1")
|
||||
val a5 = (fun(): String = "1")
|
||||
val a6: () -> Int = (fun() = 1)
|
||||
val a7: () -> Int = (fun(): String = "1") as () -> Int
|
||||
val a8: () -> Int = <!TYPE_MISMATCH!>fun(): String = "1"<!>
|
||||
val a9: () -> () -> () -> Int = <!TYPE_MISMATCH!>fun(): () -> () -> String = fun(): () -> String = fun(): String = "1"<!>
|
||||
|
||||
foo(<!TYPE_MISMATCH!>fun(): String = "1"<!>)
|
||||
foo(((<!TYPE_MISMATCH!>fun(): String = "1"<!>)))
|
||||
|
||||
val a10: Int.(String) -> Int = <!TYPE_MISMATCH!>fun (x: String) = 10<!>
|
||||
val a11: () -> () -> () -> Int = <!TYPE_MISMATCH!>fun() = fun() = fun(): String = "1"<!>
|
||||
|
||||
val a12: Int = <!TYPE_MISMATCH!>fun(): String = "1"<!>
|
||||
val a13: Int = <!TYPE_MISMATCH!>fun() = fun(): String = "1"<!>
|
||||
val a14: Int = <!TYPE_MISMATCH!>fun() = fun() = "1"<!>
|
||||
val a15: Int = <!TYPE_MISMATCH!>fun() = fun() = {}<!>
|
||||
val a16: Int = <!TYPE_MISMATCH!>fun() = fun() {}<!>
|
||||
|
||||
val a17: () -> Unit = fun() {}
|
||||
val a18: () -> Int = <!TYPE_MISMATCH!>fun() {}<!>
|
||||
val a19: () -> () -> Int = <!TYPE_MISMATCH!>fun() = fun() {}<!>
|
||||
val a20: () -> () -> () -> Unit = fun() = fun() = {}
|
||||
val a21: () -> () -> () -> Int = <!TYPE_MISMATCH!>fun() = fun() = {}<!>
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ x: () -> kotlin.Int): kotlin.Unit
|
||||
public fun </*0*/ T> id(/*0*/ x: T): T
|
||||
public fun main(): kotlin.Unit
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun take(fn: () -> List<String>) {}
|
||||
fun <L> inferFromLambda(fn: () -> L): L = TODO()
|
||||
fun <L> inferFromLambda2(fn: (Int) -> L): L = TODO()
|
||||
|
||||
fun <T> materialize(): T = TODO()
|
||||
fun <I> id(arg: I) = arg
|
||||
|
||||
fun testFunctions() {
|
||||
take { materialize() }
|
||||
take(fun() = materialize())
|
||||
take(fun(): List<String> = materialize())
|
||||
take(fun(): List<String> {
|
||||
return materialize()
|
||||
})
|
||||
}
|
||||
|
||||
fun testNestedCalls() {
|
||||
id<String>(inferFromLambda { materialize() })
|
||||
id<String>(inferFromLambda(fun() = materialize()))
|
||||
id<String>(inferFromLambda2(fun() = materialize()))
|
||||
}
|
||||
+2
-1
@@ -1,9 +1,9 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun take(fn: () -> List<String>) {}
|
||||
fun <L> inferFromLambda(fn: () -> L): L = TODO()
|
||||
fun <L> inferFromLambda2(fn: (Int) -> L): L = TODO()
|
||||
|
||||
fun <T> materialize(): T = TODO()
|
||||
fun <I> id(arg: I) = arg
|
||||
@@ -20,4 +20,5 @@ fun testFunctions() {
|
||||
fun testNestedCalls() {
|
||||
id<String>(inferFromLambda { materialize() })
|
||||
id<String>(inferFromLambda(fun() = materialize()))
|
||||
id<String>(inferFromLambda2(<!TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>fun<!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>()<!> = materialize()<!>))
|
||||
}
|
||||
|
||||
+1
@@ -2,6 +2,7 @@ package
|
||||
|
||||
public fun </*0*/ I> id(/*0*/ arg: I): I
|
||||
public fun </*0*/ L> inferFromLambda(/*0*/ fn: () -> L): L
|
||||
public fun </*0*/ L> inferFromLambda2(/*0*/ fn: (kotlin.Int) -> L): L
|
||||
public fun </*0*/ T> materialize(): T
|
||||
public fun take(/*0*/ fn: () -> kotlin.collections.List<kotlin.String>): kotlin.Unit
|
||||
public fun testFunctions(): kotlin.Unit
|
||||
|
||||
Vendored
+1
-1
@@ -153,7 +153,7 @@ fun main() {
|
||||
// Convert to extension lambda is impossible because the lambda parameter types aren't specified explicitly
|
||||
select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>x, <!CANNOT_INFER_PARAMETER_TYPE!>y<!><!> -> x }<!>)
|
||||
select(id(id(fun(x: String, y: String) { }), <!TOO_MANY_ARGUMENTS!>fun String.(x: String) {}<!>), { x, y -> x })
|
||||
val x26: Int.(String) -> Int = fun (x: String) = 10 // it must be error, see KT-38439
|
||||
val x26: Int.(String) -> Int = <!TYPE_MISMATCH!>fun (x: String) = 10<!> // it must be error, see KT-38439
|
||||
// Receiver must be specified in anonymous function declaration
|
||||
val x27: Int.(String) -> Int = id(<!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> = 10<!>)
|
||||
select(id<Int.(String) -> Unit> {}, { x: Int, y: String -> x })
|
||||
|
||||
@@ -15,7 +15,7 @@ class A() {
|
||||
|
||||
//more tests
|
||||
val g : () -> Unit = { <!UNUSED_EXPRESSION!>42<!> }
|
||||
val gFunction : () -> Unit = <!OI;TYPE_MISMATCH!>fun(): Int = 1<!>
|
||||
val gFunction : () -> Unit = <!TYPE_MISMATCH!>fun(): Int = 1<!>
|
||||
|
||||
val h : () -> Unit = { doSmth() }
|
||||
|
||||
|
||||
@@ -8202,6 +8202,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/lambdaInLambda2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("missedTypeMismatch.kt")
|
||||
public void testMissedTypeMismatch() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt")
|
||||
public void testPrematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt");
|
||||
|
||||
Generated
+5
@@ -8197,6 +8197,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/lambdaInLambda2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("missedTypeMismatch.kt")
|
||||
public void testMissedTypeMismatch() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt")
|
||||
public void testPrematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt");
|
||||
|
||||
@@ -428,9 +428,11 @@ public class TypeUtils {
|
||||
SmartSet<KotlinType> visited
|
||||
) {
|
||||
if (type == null) return false;
|
||||
if (visited != null && visited.contains(type)) return false;
|
||||
|
||||
UnwrappedType unwrappedType = type.unwrap();
|
||||
|
||||
if (noExpectedType(type)) return isSpecialType.invoke(unwrappedType);
|
||||
if (visited != null && visited.contains(type)) return false;
|
||||
if (isSpecialType.invoke(unwrappedType)) return true;
|
||||
|
||||
if (visited == null) {
|
||||
|
||||
Reference in New Issue
Block a user