diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDesignation.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDesignation.kt index 2b67fa616d0..99a7c0ba6f1 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDesignation.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDesignation.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.nullableJavaSym import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isLocalForLazyResolutionPurposes import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isScriptDependentDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.util.unwrapCopy import org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode @@ -130,11 +131,12 @@ private fun collectDesignationPath(target: FirElementWithResolveState): List { requireIsInstance(target) + // We shouldn't try to build a designation path for such fake declarations as they // do not depend on outer classes during resolution if (target.isCopyCreatedInScope) return emptyList() - if (target.symbol.callableId.isLocal || target.status.visibility == Visibilities.Local) { + if (target.symbol.isLocalForLazyResolutionPurposes) { return null } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/fir/ContextCollectingDiagnosticCollectorVisitor.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/fir/ContextCollectingDiagnosticCollectorVisitor.kt index 0da1810dc95..7e38d7a3352 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/fir/ContextCollectingDiagnosticCollectorVisitor.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/fir/ContextCollectingDiagnosticCollectorVisitor.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation import org.jetbrains.kotlin.analysis.low.level.api.fir.api.withFirDesignationEntry import org.jetbrains.kotlin.analysis.low.level.api.fir.util.containingClassIdOrNull +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isLocalForLazyResolutionPurposes import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElementWithResolveState import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider @@ -72,7 +73,7 @@ internal object PersistenceContextCollector { ): CheckerContextForProvider { val isLocal = when (declaration) { is FirClassLikeDeclaration -> declaration.symbol.classId.isLocal - is FirCallableDeclaration -> declaration.symbol.callableId.isLocal + is FirCallableDeclaration -> declaration.symbol.isLocalForLazyResolutionPurposes is FirDanglingModifierList -> declaration.containingClass()?.classId?.isLocal == true is FirAnonymousInitializer -> declaration.containingClassIdOrNull()?.isLocal == true is FirScript, is FirCodeFragment -> false diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt index b1d54bed0b0..6e5747975f6 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt @@ -9,7 +9,6 @@ import com.intellij.psi.PsiElement import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.analysis.api.impl.barebone.annotations.ThreadSafe import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureElement import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FirElementsRecorder import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.declarationCanBeLazilyResolved @@ -273,7 +272,7 @@ internal fun PsiElement.getNonLocalContainingOrThisDeclaration(predicate: (KtDec internal fun getNonLocalContainingDeclaration( elementsToCheck: Sequence, - predicate: (KtDeclaration) -> Boolean = { true } + predicate: (KtDeclaration) -> Boolean = { true }, ): KtDeclaration? { var candidate: KtDeclaration? = null @@ -303,10 +302,15 @@ internal fun getNonLocalContainingDeclaration( when (parent) { is KtScript -> propose(parent) is KtDestructuringDeclaration -> propose(parent) - is KtAnonymousInitializer -> { + is KtScriptInitializer -> { + val blockExpression = parent.parent as? KtBlockExpression + if (blockExpression?.statements?.lastOrNull() == parent && predicate(parent)) { + propose(parent) + } + } + is KtClassInitializer -> { val container = parent.containingDeclaration - if (container is KtClassOrObject && - !container.isObjectLiteral() && + if (!container.isObjectLiteral() && declarationCanBeLazilyResolved(container) && predicate(parent) ) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt index 54840fba4df..77b474dd37d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFi import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic import org.jetbrains.kotlin.fir.correspondingProperty import org.jetbrains.kotlin.fir.declarations.FirDanglingModifierList +import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor @@ -141,7 +142,15 @@ internal class FileStructure private constructor( override fun visitDeclaration(dcl: KtDeclaration) { val structureElement = getStructureElementFor(dcl) - structureElements += structureElement + + // workaround to not duplicate diagnostics in the case of FirAnonymousInitializer in the last position + // will be dropped in the context of KT-65344 + if (dcl !is KtScriptInitializer || + structureElement is DeclarationBaseStructureElement<*> && + structureElement.declaration.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty + ) { + structureElements += structureElement + } // Go down only in the case of container declaration val canHaveInnerStructure = dcl is KtClassOrObject || dcl is KtScript diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt index 09a2d7078c3..a82ee6d7369 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt @@ -86,33 +86,6 @@ internal object FirLazyBodiesCalculator { return newAnnotationCall.argumentList } - fun createResultPropertyInitializer(scriptDesignation: FirDesignation, property: FirProperty): FirExpression { - val script = scriptDesignation.target - requireWithAttachment(script is FirScript, { "${FirScript::class.simpleName} is not found" }) { - withFirDesignationEntry("designation", scriptDesignation) - withFirEntry("property", property) - } - - val propertyDesignation = FirDesignation(path = scriptDesignation.path + script, target = property) - val newInitializer = revive(propertyDesignation) - val body = newInitializer.body - requireWithAttachment(body != null, { "${FirAnonymousInitializer::class.simpleName} without body" }) { - withFirDesignationEntry("designation", propertyDesignation) - withFirEntry("initializer", newInitializer) - } - - val singleStatement = body.statements.singleOrNull() - requireWithAttachment(singleStatement is FirExpression, { "Unexpected body content" }) { - withFirDesignationEntry("designation", propertyDesignation) - withFirEntry("initializer", newInitializer) - singleStatement?.let { - withFirEntry("statement", it) - } - } - - return singleStatement - } - fun needCalculatingAnnotationCall(firAnnotationCall: FirAnnotationCall): Boolean = firAnnotationCall.argumentList.arguments.any { it is FirLazyExpression } } @@ -220,6 +193,10 @@ private fun calculateLazyBodyForConstructor(designation: FirDesignation) { private fun calculateLazyBodyForProperty(designation: FirDesignation) { val firProperty = designation.target as FirProperty if (!needCalculatingLazyBodyForProperty(firProperty)) return + if (firProperty.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty) { + calculateLazyBodyForResultProperty(firProperty, designation) + return + } val recreatedProperty = revive(designation, firProperty.unwrapFakeOverridesOrDelegated().psi) @@ -247,6 +224,26 @@ private fun calculateLazyBodyForProperty(designation: FirDesignation) { } } +private fun calculateLazyBodyForResultProperty(firProperty: FirProperty, designation: FirDesignation) { + val newInitializer = revive(designation) + val body = newInitializer.body + requireWithAttachment(body != null, { "${FirAnonymousInitializer::class.simpleName} without body" }) { + withFirDesignationEntry("designation", designation) + withFirEntry("initializer", newInitializer) + } + + val singleStatement = body.statements.singleOrNull() + requireWithAttachment(singleStatement is FirExpression, { "Unexpected body content" }) { + withFirDesignationEntry("designation", designation) + withFirEntry("initializer", newInitializer) + singleStatement?.let { + withFirEntry("statement", it) + } + } + + firProperty.replaceInitializer(singleStatement) +} + /** * This function is required to correctly rebind symbols * after [generateAccessorsByDelegate][org.jetbrains.kotlin.fir.builder.generateAccessorsByDelegate] diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt index 1555469611a..d3ea6b46038 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirEle import org.jetbrains.kotlin.analysis.low.level.api.fir.compile.codeFragmentScopeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.LLFirDeclarationModificationService -import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.util.* @@ -52,7 +51,6 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment import org.jetbrains.kotlin.utils.exceptions.withPsiEntry -import org.jetbrains.kotlin.utils.findIsInstanceAnd internal object LLFirBodyLazyResolver : LLFirLazyResolver(FirResolvePhase.BODY_RESOLVE) { override fun resolve( @@ -351,24 +349,10 @@ internal object BodyStateKeepers { val oldDeclarations = script.declarations if (oldDeclarations.none { it.isElementWhichShouldBeResolvedAsPartOfScript }) return@stateKeeper - val resultProperty = script.findResultProperty() - if (resultProperty != null && resultProperty.bodyResolveState != FirPropertyBodyResolveState.ALL_BODIES_RESOLVED) { - entity(resultProperty, RESULT_PROPERTY, designation) - } - entityList(oldDeclarations.mapNotNull { it as? FirAnonymousInitializer }, ANONYMOUS_INITIALIZER, designation) add(FirScript::controlFlowGraphReference, FirScript::replaceControlFlowGraphReference) } - private val RESULT_PROPERTY: StateKeeper = stateKeeper { property, scriptDesignation -> - add(FirProperty::bodyResolveState, FirProperty::replaceBodyResolveState) - add(FirProperty::returnTypeRef, FirProperty::replaceReturnTypeRef) - add(FirProperty::controlFlowGraphReference, FirProperty::replaceControlFlowGraphReference) - add(FirProperty::initializer, FirProperty::replaceInitializer) { _ -> - FirLazyBodiesCalculator.createResultPropertyInitializer(scriptDesignation, property) - } - } - val CODE_FRAGMENT: StateKeeper = stateKeeper { _, _ -> add(FirCodeFragment::block, FirCodeFragment::replaceBlock, ::blockGuard) } @@ -483,10 +467,6 @@ private fun StateKeeperScope.preserveContractBlock( } } -private fun FirScript.findResultProperty(): FirProperty? = declarations.findIsInstanceAnd { - it.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty -} - private val FirFunction.isCertainlyResolved: Boolean get() { if (this is FirPropertyAccessor) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/PostponedSymbolsForAnnotationResolutionAttribute.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/PostponedSymbolsForAnnotationResolutionAttribute.kt index 781133d1fe9..d407791b221 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/PostponedSymbolsForAnnotationResolutionAttribute.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/PostponedSymbolsForAnnotationResolutionAttribute.kt @@ -6,11 +6,11 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers import org.jetbrains.kotlin.analysis.low.level.api.fir.util.forEachDependentDeclaration +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isLocalForLazyResolutionPurposes import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry -import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirScript import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -59,7 +59,7 @@ internal var FirCallableDeclaration.postponedSymbolsForAnnotationResolution: Col * @return true if this symbol shouldn't be processed as the owner of an annotation call */ internal fun FirBasedSymbol<*>.cannotResolveAnnotationsOnDemand(): Boolean { - return this is FirCallableSymbol<*> && callableId.isLocal && fir.origin != FirDeclarationOrigin.ScriptCustomization.ResultProperty + return this is FirCallableSymbol<*> && isLocalForLazyResolutionPurposes } /** diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt index f5fb19cc758..d96635cb05b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt @@ -16,17 +16,18 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLoc import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.isAutonomousDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirFileBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirProvider +import org.jetbrains.kotlin.analysis.utils.printer.parentOfType +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.resolve.providers.FirProvider +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol -import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.parameterIndex -import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment internal fun KtDeclaration.findSourceNonLocalFirDeclaration( firFileBuilder: LLFirFileBuilder, @@ -122,7 +123,7 @@ private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider( is KtProperty, is KtNamedFunction, is KtConstructor<*>, - is KtClassInitializer, + is KtAnonymousInitializer, is KtTypeAlias, is KtDestructuringDeclaration, is KtScript, @@ -231,7 +232,18 @@ internal inline fun FirDeclaration.forEachDeclaration(action: (FirDeclaration) - internal val FirDeclaration.isElementWhichShouldBeResolvedAsPartOfScript: Boolean get() = this is FirAnonymousInitializer || isScriptDependentDeclaration internal val FirDeclaration.isScriptDependentDeclaration: Boolean - get() = origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty + get() = false + +/** + * Some "local" declarations are not local from the lazy resolution perspective. + */ +internal val FirCallableSymbol<*>.isLocalForLazyResolutionPurposes: Boolean + get() = when { + // We should treat result$$ property as non-local explicitly as its CallableId is local + // TODO: can be dropped after KT-65523 + fir.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty -> false + else -> callableId.isLocal || fir.status.visibility == Visibilities.Local + } internal inline fun FirScript.forEachDependentDeclaration(action: (FirDeclaration) -> Unit) { for (declaration in declarations) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firCheckResolvedUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firCheckResolvedUtils.kt index 9143b0ce131..2f6f0ee4bbb 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firCheckResolvedUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firCheckResolvedUtils.kt @@ -115,7 +115,6 @@ internal fun checkStatementsAreResolved(script: FirScript) { } for (declaration in script.declarations) { if (declaration.isScriptDependentDeclaration) { - (declaration as? FirProperty)?.initializer?.let(::checkExpression) } else if (declaration is FirAnonymousInitializer) { declaration.body?.statements?.filterIsInstance()?.forEach(::checkExpression) } diff --git a/analysis/low-level-api-fir/testData/contextCollector/scripts/lastStatement.copy.txt b/analysis/low-level-api-fir/testData/contextCollector/scripts/lastStatement.copy.txt index 3f11f1abef9..d26123c280d 100644 --- a/analysis/low-level-api-fir/testData/contextCollector/scripts/lastStatement.copy.txt +++ b/analysis/low-level-api-fir/testData/contextCollector/scripts/lastStatement.copy.txt @@ -14,22 +14,16 @@ Tower Data Context: Element 6 Scope: FirScriptDeclarationsScope Classifiers: - FirRegularClassSymbol public final class ScriptClass : R|kotlin/Any| + FirRegularClassSymbol public final? class ScriptClass : R|kotlin/Any| Functions FirNamedFunctionSymbol public final fun foo(i: R|kotlin/Int|, action: R|(kotlin/Int) -> kotlin/Unit|): R|kotlin/Unit| FirNamedFunctionSymbol public final fun scriptFunction(): R|kotlin/Int| - FirNamedFunctionSymbol public final fun unusedScriptFunction(p: R|kotlin/String|): R|kotlin/Int| + FirNamedFunctionSymbol public? final? fun unusedScriptFunction(p: String): Properties: FirPropertySymbol public final val $$result: R|kotlin/Unit| public get(): R|kotlin/Unit| Element 7 Scope: FirLocalScope - Classifiers: - FirRegularClassSymbol public final class ScriptClass : R|kotlin/Any| - Functions - FirNamedFunctionSymbol public final fun foo(i: R|kotlin/Int|, action: R|(kotlin/Int) -> kotlin/Unit|): R|kotlin/Unit| - FirNamedFunctionSymbol public final fun scriptFunction(): R|kotlin/Int| - FirNamedFunctionSymbol public final fun unusedScriptFunction(p: R|kotlin/String|): R|kotlin/Int| Properties: FirPropertySymbol lval args: R|kotlin/Array| Element 8 @@ -38,9 +32,9 @@ Tower Data Context: SCRIPT: lval args: R|kotlin/Array| - public final class ScriptClass : R|kotlin/Any| + public final? class ScriptClass : R|kotlin/Any| public final fun scriptFunction(): R|kotlin/Int| - public final fun unusedScriptFunction(p: R|kotlin/String|): R|kotlin/Int| + public? final? fun unusedScriptFunction(p: String): init public final fun foo(i: R|kotlin/Int|, action: R|(kotlin/Int) -> kotlin/Unit|): R|kotlin/Unit| public final val $$result: R|kotlin/Unit| @@ -49,35 +43,27 @@ Tower Data Context: Label: