[FIR] Assert source is not-null when reporting cone diagnostics

#KT-55835
#KT-59856
This commit is contained in:
Kirill Rakhman
2023-07-18 10:23:30 +02:00
committed by Space Team
parent 2f3293f99e
commit 9288a96f6d
10 changed files with 70 additions and 72 deletions
@@ -1,4 +1,3 @@
// COMPARE_WITH_LIGHT_TREE
interface A
class B<T> where T : A
@@ -15,7 +14,7 @@ fun test() {
val b1 = B<<!UPPER_BOUND_VIOLATED!>Int<!>>()
val b2 = B<C>()
val b3 = B<<!UPPER_BOUND_VIOLATED!>Any?<!>>()
val b4 = B<<!UNRESOLVED_REFERENCE!>UnexistingType<!>>()<!UNRESOLVED_REFERENCE!>NL<!><!SYNTAX!><<!>Int<!SYNTAX{LT}!><!SYNTAX!>><!>()<!>NumberPhile<!SYNTAX!><!>
val b4 = B<<!UNRESOLVED_REFERENCE!>UnexistingType<!>>()<!UNRESOLVED_REFERENCE!>NL<!><!SYNTAX!><<!>Int<!SYNTAX!><!SYNTAX!>><!>()<!>NumberPhile<!SYNTAX!><!>
val b5 = B<<!UPPER_BOUND_VIOLATED!>B<<!UNRESOLVED_REFERENCE!>UnexistingType<!>><!>>()
fest<<!UPPER_BOUND_VIOLATED!>Boolean<!>>()
fest<C>()
@@ -13,14 +13,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorImport
import org.jetbrains.kotlin.fir.declarations.FirErrorProperty
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.diagnostics.ConeAmbiguousSuper
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirNamedReference
@@ -33,12 +27,12 @@ class ErrorNodeDiagnosticCollectorComponent(
reporter: DiagnosticReporter,
) : AbstractDiagnosticCollectorComponent(session, reporter) {
override fun visitErrorLoop(errorLoop: FirErrorLoop, data: CheckerContext) {
val source = errorLoop.source ?: return
val source = errorLoop.source
reportFirDiagnostic(errorLoop.diagnostic, source, data)
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: CheckerContext) {
val source = errorTypeRef.source ?: return
val source = errorTypeRef.source
reportFirDiagnostic(errorTypeRef.diagnostic, source, data)
}
@@ -49,7 +43,7 @@ class ErrorNodeDiagnosticCollectorComponent(
}
override fun visitErrorAnnotationCall(errorAnnotationCall: FirErrorAnnotationCall, data: CheckerContext) {
val source = errorAnnotationCall.source ?: return
val source = errorAnnotationCall.source
reportFirDiagnostic(errorAnnotationCall.diagnostic, source, data)
}
@@ -62,15 +56,15 @@ class ErrorNodeDiagnosticCollectorComponent(
}
private fun processErrorReference(reference: FirNamedReference, diagnostic: ConeDiagnostic, context: CheckerContext) {
var source = reference.source ?: return
var source = reference.source
val callOrAssignment = context.callsOrAssignments.lastOrNull()?.takeIf {
// Use the source of the enclosing FirQualifiedAccess if it is exactly the call to the erroneous callee.
it.calleeReference == reference
}
// Don't report duplicated unresolved reference on annotation entry (already reported on its type)
if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && diagnostic is ConeUnresolvedNameError) return
if (source?.elementType == KtNodeTypes.ANNOTATION_ENTRY && diagnostic is ConeUnresolvedNameError) return
// Already reported in FirConventionFunctionCallChecker
if (source.kind == KtFakeSourceElementKind.ArrayAccessNameReference &&
if (source?.kind == KtFakeSourceElementKind.ArrayAccessNameReference &&
diagnostic is ConeUnresolvedNameError
) return
@@ -82,7 +76,7 @@ class ErrorNodeDiagnosticCollectorComponent(
) return
}
if (source.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor) {
if (source?.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor) {
val property = context.containingDeclarations.lastOrNull { it is FirProperty } as? FirProperty ?: return
source = property.delegate?.source?.fakeElement(KtFakeSourceElementKind.DelegatedPropertyAccessor) ?: return
}
@@ -101,55 +95,62 @@ class ErrorNodeDiagnosticCollectorComponent(
}
override fun visitErrorExpression(errorExpression: FirErrorExpression, data: CheckerContext) {
val source = errorExpression.source ?: return
reportFirDiagnostic(errorExpression.diagnostic, source, data)
val source = errorExpression.source
val diagnostic = errorExpression.diagnostic
if (source == null) {
// ConeSyntaxDiagnostic and DiagnosticKind.ExpressionExpected with no source (see check above) are typically symptoms of some
// syntax error that was already reported during parsing.
if (diagnostic is ConeSyntaxDiagnostic) return
if (diagnostic is ConeSimpleDiagnostic && diagnostic.kind == DiagnosticKind.ExpressionExpected) return
}
reportFirDiagnostic(diagnostic, source, data)
}
override fun visitErrorFunction(errorFunction: FirErrorFunction, data: CheckerContext) {
val source = errorFunction.source ?: return
val source = errorFunction.source
reportFirDiagnostic(errorFunction.diagnostic, source, data)
}
override fun visitErrorProperty(errorProperty: FirErrorProperty, data: CheckerContext) {
val source = errorProperty.source ?: return
val source = errorProperty.source
reportFirDiagnostic(errorProperty.diagnostic, source, data)
}
override fun visitErrorResolvedQualifier(errorResolvedQualifier: FirErrorResolvedQualifier, data: CheckerContext) {
val source = errorResolvedQualifier.source ?: return
val source = errorResolvedQualifier.source
reportFirDiagnostic(errorResolvedQualifier.diagnostic, source, data)
}
override fun visitErrorImport(errorImport: FirErrorImport, data: CheckerContext) {
val source = errorImport.source ?: return
val source = errorImport.source
reportFirDiagnostic(errorImport.diagnostic, source, data)
}
private fun reportFirDiagnostic(
diagnostic: ConeDiagnostic,
source: KtSourceElement,
source: KtSourceElement?,
context: CheckerContext,
callOrAssignmentSource: KtSourceElement? = null
) {
// Will be handled by [FirDestructuringDeclarationChecker]
if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY) {
if (source?.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY) {
return
}
// Will be handled by [FirDelegatedPropertyChecker]
if (source.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor &&
if (source?.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor &&
(diagnostic is ConeUnresolvedNameError || diagnostic is ConeAmbiguityError || diagnostic is ConeInapplicableWrongReceiver || diagnostic is ConeInapplicableCandidateError)
) {
return
}
if (source.kind == KtFakeSourceElementKind.ImplicitConstructor || source.kind == KtFakeSourceElementKind.DesugaredForLoop) {
if (source?.kind == KtFakeSourceElementKind.ImplicitConstructor || source?.kind == KtFakeSourceElementKind.DesugaredForLoop) {
// See FirForLoopChecker
return
}
// Prefix inc/dec on array access will have two calls to .get(...), don't report for the second one.
if (source.kind == KtFakeSourceElementKind.DesugaredPrefixSecondGetReference) {
if (source?.kind == KtFakeSourceElementKind.DesugaredPrefixSecondGetReference) {
return
}
@@ -45,7 +45,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
private fun ConeDiagnostic.toKtDiagnostic(
source: KtSourceElement,
source: KtSourceElement?,
callOrAssignmentSource: KtSourceElement?
): KtDiagnostic? = when (this) {
is ConeUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.createOn(
@@ -118,7 +118,7 @@ private fun ConeDiagnostic.toKtDiagnostic(
is ConeSyntaxDiagnostic -> FirSyntaxErrors.SYNTAX.createOn(callOrAssignmentSource ?: source, reason)
is ConeSimpleDiagnostic -> when {
source.kind is KtFakeSourceElementKind && source.kind != KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess -> null
source?.kind is KtFakeSourceElementKind && source.kind != KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess -> null
else -> this.getFactory(source).createOn(callOrAssignmentSource ?: source)
}
@@ -162,7 +162,7 @@ fun FirBasedSymbol<*>.toInvisibleReferenceDiagnostic(source: KtSourceElement?):
fun ConeDiagnostic.toFirDiagnostics(
session: FirSession,
source: KtSourceElement,
source: KtSourceElement?,
callOrAssignmentSource: KtSourceElement?
): List<KtDiagnostic> {
return when (this) {
@@ -175,9 +175,9 @@ fun ConeDiagnostic.toFirDiagnostics(
private fun mapUnsafeCallError(
candidate: AbstractCandidate,
rootCause: UnsafeCall,
source: KtSourceElement,
source: KtSourceElement?,
qualifiedAccessSource: KtSourceElement?,
): KtDiagnostic? {
): KtDiagnostic {
if (candidate.callInfo.isImplicitInvoke) {
return FirErrors.UNSAFE_IMPLICIT_INVOKE_CALL.createOn(source, rootCause.actualType)
}
@@ -187,14 +187,14 @@ private fun mapUnsafeCallError(
val receiverExpression = candidate.callInfo.explicitReceiver
val singleArgument = candidate.callInfo.argumentList.arguments.singleOrNull()
if (receiverExpression != null && singleArgument != null &&
(source.elementType == KtNodeTypes.OPERATION_REFERENCE || source.elementType == KtNodeTypes.BINARY_EXPRESSION) &&
(source?.elementType == KtNodeTypes.OPERATION_REFERENCE || source?.elementType == KtNodeTypes.BINARY_EXPRESSION) &&
(candidateFunctionSymbol?.isOperator == true || candidateFunctionSymbol?.isInfix == true)
) {
// For augmented assignment operations (e.g., `a += b`), the source is the entire binary expression (BINARY_EXPRESSION).
// TODO, KT-59809: No need to check for source.elementType == BINARY_EXPRESSION if we use operator as callee reference source
// (see FirExpressionsResolveTransformer.transformAssignmentOperatorStatement)
val operationSource = if (source.elementType == KtNodeTypes.BINARY_EXPRESSION) {
source.getChild(KtNodeTypes.OPERATION_REFERENCE)
val operationSource = if (source?.elementType == KtNodeTypes.BINARY_EXPRESSION) {
source?.getChild(KtNodeTypes.OPERATION_REFERENCE)
} else {
source
}
@@ -216,7 +216,7 @@ private fun mapUnsafeCallError(
)
}
}
return if (source.kind == KtFakeSourceElementKind.ArrayAccessNameReference) {
return if (source?.kind == KtFakeSourceElementKind.ArrayAccessNameReference) {
FirErrors.UNSAFE_CALL.createOn(source, rootCause.actualType, receiverExpression)
} else {
FirErrors.UNSAFE_CALL.createOn(qualifiedAccessSource ?: source, rootCause.actualType, receiverExpression)
@@ -226,7 +226,7 @@ private fun mapUnsafeCallError(
private fun mapInapplicableCandidateError(
session: FirSession,
diagnostic: ConeInapplicableCandidateError,
source: KtSourceElement,
source: KtSourceElement?,
qualifiedAccessSource: KtSourceElement?,
): List<KtDiagnostic> {
val typeContext = session.typeContext
@@ -341,7 +341,7 @@ private fun mapInapplicableCandidateError(
private fun mapSystemHasContradictionError(
session: FirSession,
diagnostic: ConeConstraintSystemHasContradiction,
source: KtSourceElement,
source: KtSourceElement?,
qualifiedAccessSource: KtSourceElement?,
): List<KtDiagnostic> {
return buildList {
@@ -380,7 +380,7 @@ private fun mapSystemHasContradictionError(
}
private fun ConstraintSystemError.toDiagnostic(
source: KtSourceElement,
source: KtSourceElement?,
qualifiedAccessSource: KtSourceElement?,
typeContext: ConeTypeContext,
candidate: AbstractCandidate,
@@ -507,7 +507,7 @@ private fun findInferredEmptyIntersectionNarrowedSource(
}
private fun reportInferredIntoEmptyIntersection(
source: KtSourceElement,
source: KtSourceElement?,
typeVariable: ConeTypeVariable,
incompatibleTypes: Collection<ConeKotlinType>,
causingTypes: Collection<ConeKotlinType>,
@@ -531,7 +531,7 @@ private fun reportInferredIntoEmptyIntersection(
private val NewConstraintError.lowerConeType: ConeKotlinType get() = lowerType as ConeKotlinType
private val NewConstraintError.upperConeType: ConeKotlinType get() = upperType as ConeKotlinType
private fun ConeSimpleDiagnostic.getFactory(source: KtSourceElement): KtDiagnosticFactory0 {
private fun ConeSimpleDiagnostic.getFactory(source: KtSourceElement?): KtDiagnosticFactory0 {
return when (kind) {
DiagnosticKind.ReturnNotAllowed -> FirErrors.RETURN_NOT_ALLOWED
DiagnosticKind.NotAFunctionLabel -> FirErrors.NOT_A_FUNCTION_LABEL
@@ -544,7 +544,7 @@ private fun ConeSimpleDiagnostic.getFactory(source: KtSourceElement): KtDiagnost
DiagnosticKind.RecursionInImplicitTypes -> FirErrors.RECURSION_IN_IMPLICIT_TYPES
DiagnosticKind.Java -> FirErrors.ERROR_FROM_JAVA_RESOLUTION
DiagnosticKind.SuperNotAllowed -> FirErrors.SUPER_IS_NOT_AN_EXPRESSION
DiagnosticKind.ExpressionExpected -> when (source.elementType) {
DiagnosticKind.ExpressionExpected -> when (source?.elementType) {
KtNodeTypes.BINARY_EXPRESSION -> FirErrors.ASSIGNMENT_IN_EXPRESSION_CONTEXT
KtNodeTypes.FUN -> FirErrors.ANONYMOUS_FUNCTION_WITH_NAME
KtNodeTypes.WHEN_CONDITION_IN_RANGE, KtNodeTypes.WHEN_CONDITION_IS_PATTERN, KtNodeTypes.WHEN_CONDITION_EXPRESSION ->
@@ -586,16 +586,16 @@ private fun ConeSimpleDiagnostic.getFactory(source: KtSourceElement): KtDiagnost
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun KtDiagnosticFactory0.createOn(
element: KtSourceElement?
): KtSimpleDiagnostic? {
return element?.let { on(it, positioningStrategy = null) }
): KtSimpleDiagnostic {
return on(element.requireNotNull(), positioningStrategy = null)
}
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun <A> KtDiagnosticFactory1<A>.createOn(
element: KtSourceElement?,
a: A
): KtDiagnosticWithParameters1<A>? {
return element?.let { on(it, a, positioningStrategy = null) }
): KtDiagnosticWithParameters1<A> {
return on(element.requireNotNull(), a, positioningStrategy = null)
}
@OptIn(InternalDiagnosticFactoryMethod::class)
@@ -603,8 +603,8 @@ private fun <A, B> KtDiagnosticFactory2<A, B>.createOn(
element: KtSourceElement?,
a: A,
b: B
): KtDiagnosticWithParameters2<A, B>? {
return element?.let { on(it, a, b, positioningStrategy = null) }
): KtDiagnosticWithParameters2<A, B> {
return on(element.requireNotNull(), a, b, positioningStrategy = null)
}
@OptIn(InternalDiagnosticFactoryMethod::class)
@@ -613,8 +613,8 @@ private fun <A, B, C> KtDiagnosticFactory3<A, B, C>.createOn(
a: A,
b: B,
c: C
): KtDiagnosticWithParameters3<A, B, C>? {
return element?.let { on(it, a, b, c, positioningStrategy = null) }
): KtDiagnosticWithParameters3<A, B, C> {
return on(element.requireNotNull(), a, b, c, positioningStrategy = null)
}
@OptIn(InternalDiagnosticFactoryMethod::class)
@@ -624,6 +624,6 @@ private fun <A, B, C, D> KtDiagnosticFactory4<A, B, C, D>.createOn(
b: B,
c: C,
d: D
): KtDiagnosticWithParameters4<A, B, C, D>? {
return element?.let { on(it, a, b, c, d, positioningStrategy = null) }
): KtDiagnosticWithParameters4<A, B, C, D> {
return on(element.requireNotNull(), a, b, c, d, positioningStrategy = null)
}
@@ -66,7 +66,8 @@ class LightTreeRawFirExpressionBuilder(
return converted as? R
?: buildErrorExpression(
expression?.toFirSourceElement(),
ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected),
if (expression == null) ConeSyntaxDiagnostic(errorReason)
else ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected),
converted,
) as R
}
@@ -116,7 +117,7 @@ class LightTreeRawFirExpressionBuilder(
OBJECT_LITERAL -> declarationBuilder.convertObjectLiteral(expression)
FUN -> declarationBuilder.convertFunctionDeclaration(expression)
DESTRUCTURING_DECLARATION -> declarationBuilder.convertDestructingDeclaration(expression).toFirDestructingDeclaration(baseModuleData)
else -> buildErrorExpression(null, ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected))
else -> buildErrorExpression(expression.toFirSourceElement(KtFakeSourceElementKind.ErrorTypeRef), ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected))
}
}
@@ -50,7 +50,7 @@ import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ArrayFqNames
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.Variance
class FirSyntheticCallGenerator(
@@ -259,17 +259,18 @@ class FirSyntheticCallGenerator(
val callInfo = generateCallInfo(callSite, name, argumentList, callKind)
val candidate = generateCandidate(callInfo, function, context)
val applicability = components.resolutionStageRunner.processCandidate(candidate, context)
if (applicability <= CandidateApplicability.INAPPLICABLE) {
val source = callSite.source?.fakeElement(KtFakeSourceElementKind.SyntheticCall)
if (!applicability.isSuccess) {
return createErrorReferenceWithExistingCandidate(
candidate,
ConeInapplicableCandidateError(applicability, candidate),
source = null,
source,
context,
components.resolutionStageRunner
)
}
return FirNamedReferenceWithCandidate(callSite.source?.fakeElement(KtFakeSourceElementKind.SyntheticCall), name, candidate)
return FirNamedReferenceWithCandidate(source, name, candidate)
}
private fun generateCandidate(callInfo: CallInfo, function: FirSimpleFunction, context: ResolutionContext): Candidate {
@@ -15,7 +15,7 @@ fun DiagnosticReporter.reportOn(
context: DiagnosticContext,
positioningStrategy: AbstractSourceElementPositioningStrategy? = null
) {
report(factory.on(requireSourceNotNull(source), positioningStrategy), context)
report(factory.on(source.requireNotNull(), positioningStrategy), context)
}
fun <A : Any> DiagnosticReporter.reportOn(
@@ -25,7 +25,7 @@ fun <A : Any> DiagnosticReporter.reportOn(
context: DiagnosticContext,
positioningStrategy: AbstractSourceElementPositioningStrategy? = null
) {
report(factory.on(requireSourceNotNull(source), a, positioningStrategy), context)
report(factory.on(source.requireNotNull(), a, positioningStrategy), context)
}
fun <A : Any, B : Any> DiagnosticReporter.reportOn(
@@ -36,7 +36,7 @@ fun <A : Any, B : Any> DiagnosticReporter.reportOn(
context: DiagnosticContext,
positioningStrategy: AbstractSourceElementPositioningStrategy? = null
) {
report(factory.on(requireSourceNotNull(source), a, b, positioningStrategy), context)
report(factory.on(source.requireNotNull(), a, b, positioningStrategy), context)
}
fun <A : Any, B : Any, C : Any> DiagnosticReporter.reportOn(
@@ -48,7 +48,7 @@ fun <A : Any, B : Any, C : Any> DiagnosticReporter.reportOn(
context: DiagnosticContext,
positioningStrategy: AbstractSourceElementPositioningStrategy? = null
) {
report(factory.on(requireSourceNotNull(source), a, b, c, positioningStrategy), context)
report(factory.on(source.requireNotNull(), a, b, c, positioningStrategy), context)
}
fun <A : Any, B : Any, C : Any, D : Any> DiagnosticReporter.reportOn(
@@ -61,11 +61,11 @@ fun <A : Any, B : Any, C : Any, D : Any> DiagnosticReporter.reportOn(
context: DiagnosticContext,
positioningStrategy: AbstractSourceElementPositioningStrategy? = null
) {
report(factory.on(requireSourceNotNull(source), a, b, c, d, positioningStrategy), context)
report(factory.on(source.requireNotNull(), a, b, c, d, positioningStrategy), context)
}
private fun requireSourceNotNull(source: AbstractKtSourceElement?): AbstractKtSourceElement =
requireNotNull(source) { "source must not be null" }
fun AbstractKtSourceElement?.requireNotNull(): AbstractKtSourceElement =
requireNotNull(this) { "source must not be null" }
fun DiagnosticReporter.reportOn(
source: AbstractKtSourceElement?,
@@ -1,6 +1,5 @@
// COMPARE_WITH_LIGHT_TREE
// !DIAGNOSTICS: -UNUSED_VARIABLE
fun main() {
val list = <!UNRESOLVED_REFERENCE!>mutable<!> ListOf<!SYNTAX!><<!>Int<!SYNTAX{LT}!><!SYNTAX!>><!>(1) {}<!>
val list = <!UNRESOLVED_REFERENCE!>mutable<!> ListOf<!SYNTAX!><<!>Int<!SYNTAX!><!SYNTAX!>><!>(1) {}<!>
}
@@ -1,4 +1,3 @@
// COMPARE_WITH_LIGHT_TREE
// !DIAGNOSTICS: -UNUSED_VARIABLE
fun main() {
@@ -1,4 +1,3 @@
// NI_EXPECTED_FILE
// COMPARE_WITH_LIGHT_TREE
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!>.<!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>cabc<!><!SYNTAX{LT}!><!SYNTAX!>$Wrapper<!><<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>out Any<!>><!>::<!UNRESOLVED_REFERENCE!>unwrap<!>
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!>.<!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>cabc<!><!SYNTAX!><!SYNTAX!>$Wrapper<!><<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>out Any<!>><!>::<!UNRESOLVED_REFERENCE!>unwrap<!>
@@ -1,4 +1,3 @@
// NI_EXPECTED_FILE
// COMPARE_WITH_LIGHT_TREE
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!>.<!SYNTAX!><<!><!DEBUG_INFO_MISSING_UNRESOLVED!>cabc<!><!SYNTAX!>$Wrapper<!><out <!DEBUG_INFO_MISSING_UNRESOLVED!>Any<!>>::<!DEBUG_INFO_MISSING_UNRESOLVED!>unwrap<!>