Support for simple cases when a namespace creates classes from other namespaces.

This commit is contained in:
Pavel V. Talanov
2012-03-19 15:44:02 +04:00
parent 6f87634b25
commit 02da9b42c1
16 changed files with 164 additions and 117 deletions
@@ -40,9 +40,20 @@ public class MultiNamespaceTest extends MultipleFilesTranslationTest {
checkFooBoxIsTrue("namespaceVariableVisibleFromOtherNamespace");
}
public void testNestedNamespaceFunctionCalledFromOtherNamespace() throws Exception {
checkFooBoxIsTrue("nestedNamespaceFunctionCalledFromOtherNamespace");
runMultiFileTest("nestedNamespaceFunctionCalledFromOtherNamespace", "a.foo", "box", true);
}
public void testSubnamespacesWithClashingNames() throws Exception {
runMultiFileTest("subnamespacesWithClashingNames", "a.foo", "box", true);
}
public void testSubnamespacesWithClashingNamesUsingImport() throws Exception {
runMultiFileTest("subnamespacesWithClashingNamesUsingImport", "a.foo", "box", true);
}
public void testCreateClassFromOtherNamespace() throws Exception {
runMultiFileTest("createClassFromOtherNamespace", "a.foo", "box", true);
}
}
@@ -37,4 +37,9 @@ public final class NamespaceTest extends SingleFileTranslationTest {
public void testDeeplyNestedNamespaceFunctionCalled() throws Exception {
runFunctionOutputTest("deeplyNestedNamespaceFunctionCalled.kt", "foo1.foo2.foo3.foo5.foo6.foo7.foo8", "box", true);
}
public void testClassCreatedInDeeplyNestedNamespace() throws Exception {
runFunctionOutputTest("classCreatedInDeeplyNestedNamespace.kt", "foo1.foo2.foo3.foo5.foo6.foo7.foo8", "box", true);
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.k2js.translate.context.generator.Generator;
import org.jetbrains.k2js.translate.context.generator.Rule;
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
import org.jetbrains.k2js.translate.utils.DescriptorUtils;
import org.jetbrains.k2js.translate.utils.JsAstUtils;
import org.jetbrains.k2js.translate.utils.PredefinedAnnotation;
@@ -51,7 +52,7 @@ public final class StaticContext {
NamingScope scope = NamingScope.rootScope(jsRootScope);
Intrinsics intrinsics = Intrinsics.standardLibraryIntrinsics(library);
StandardClasses standardClasses =
StandardClasses.bindImplementations(namer.getKotlinScope());
StandardClasses.bindImplementations(namer.getKotlinScope());
return new StaticContext(program, bindingContext, aliaser,
namer, intrinsics, standardClasses, scope);
}
@@ -174,7 +175,7 @@ public final class StaticContext {
if (!(descriptor instanceof NamespaceDescriptor)) {
return null;
}
String nameForNamespace = getNameForNamespace((NamespaceDescriptor) descriptor);
String nameForNamespace = getNameForNamespace((NamespaceDescriptor)descriptor);
return getRootScope().declareUnobfuscatableName(nameForNamespace);
}
};
@@ -204,7 +205,7 @@ public final class StaticContext {
return null;
}
boolean isGetter = descriptor instanceof PropertyGetterDescriptor;
String propertyName = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty().getName();
String propertyName = ((PropertyAccessorDescriptor)descriptor).getCorrespondingProperty().getName();
String accessorName = Namer.getNameForAccessor(propertyName, isGetter);
NamingScope enclosingScope = getEnclosingScope(descriptor);
return enclosingScope.declareObfuscatableName(accessorName);
@@ -245,12 +246,11 @@ public final class StaticContext {
if (!descriptor.getName().equals("toString")) {
return null;
}
if (((FunctionDescriptor) descriptor).getValueParameters().isEmpty()) {
if (((FunctionDescriptor)descriptor).getValueParameters().isEmpty()) {
return getEnclosingScope(descriptor).declareUnobfuscatableName("toString");
}
return null;
}
};
Rule<JsName> overridingDescriptorsReferToOriginalName = new Rule<JsName>() {
@@ -260,7 +260,7 @@ public final class StaticContext {
if (!(descriptor instanceof FunctionDescriptor)) {
return null;
}
FunctionDescriptor overriddenDescriptor = getOverriddenDescriptor((FunctionDescriptor) descriptor);
FunctionDescriptor overriddenDescriptor = getOverriddenDescriptor((FunctionDescriptor)descriptor);
if (overriddenDescriptor == null) {
return null;
}
@@ -295,7 +295,7 @@ public final class StaticContext {
if (!(descriptor instanceof ClassDescriptor)) {
return null;
}
if (getSuperclass((ClassDescriptor) descriptor) == null) {
if (getSuperclass((ClassDescriptor)descriptor) == null) {
return getRootScope().innerScope("Scope for class " + descriptor.getName());
}
return null;
@@ -307,7 +307,7 @@ public final class StaticContext {
if (!(descriptor instanceof ClassDescriptor)) {
return null;
}
ClassDescriptor superclass = getSuperclass((ClassDescriptor) descriptor);
ClassDescriptor superclass = getSuperclass((ClassDescriptor)descriptor);
if (superclass == null) {
return null;
}
@@ -354,7 +354,7 @@ public final class StaticContext {
@Nullable
public JsNameRef getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) {
if (qualifierIsNull.get(descriptor) != null) {
if (qualifierIsNull.get(descriptor.getOriginal()) != null) {
return null;
}
return qualifiers.get(descriptor.getOriginal());
@@ -362,7 +362,7 @@ public final class StaticContext {
private final class QualifierGenerator extends Generator<JsNameRef> {
public QualifierGenerator() {
Rule<JsNameRef> namespacesHaveNoQualifiers = new Rule<JsNameRef>() {
Rule<JsNameRef> standardObjectsHaveKotlinQualifier = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
if (!standardClasses.isStandardObject(descriptor)) {
@@ -379,7 +379,9 @@ public final class StaticContext {
return null;
}
JsName containingDeclarationName = getNameForDescriptor(containingDeclaration);
return containingDeclarationName.makeRef();
JsNameRef qualifier = containingDeclarationName.makeRef();
qualifier.setQualifier(getQualifierForDescriptor(containingDeclaration));
return qualifier;
}
};
Rule<JsNameRef> constructorHaveTheSameQualifierAsTheClass = new Rule<JsNameRef>() {
@@ -405,7 +407,7 @@ public final class StaticContext {
};
addRule(libraryObjectsHaveKotlinQualifier);
addRule(constructorHaveTheSameQualifierAsTheClass);
addRule(namespacesHaveNoQualifiers);
addRule(standardObjectsHaveKotlinQualifier);
addRule(namespaceLevelDeclarationsHaveEnclosingNamespacesNamesAsQualifier);
}
}
@@ -441,6 +443,19 @@ public final class StaticContext {
return true;
}
};
Rule<Boolean> topLevelNamespaceHaveNoQualifier = new Rule<Boolean>() {
@Override
public Boolean apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof NamespaceDescriptor)) {
return null;
}
if (DescriptorUtils.isTopLevelNamespace((NamespaceDescriptor)descriptor)) {
return true;
}
return null;
}
};
addRule(topLevelNamespaceHaveNoQualifier);
addRule(propertiesHaveNoQualifiers);
addRule(variableAsFunctionsHaveNoQualifiers);
addRule(nativeObjectsHaveNoQualifiers);
@@ -76,7 +76,7 @@ public final class TranslationContext {
@NotNull
public JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof CallableDescriptor) {
return getFunctionObject((CallableDescriptor) descriptor).getBody();
return getFunctionObject((CallableDescriptor)descriptor).getBody();
}
else {
return new JsBlock();
@@ -111,7 +111,7 @@ public final class TranslationContext {
@Nullable
public JsNameRef getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) {
return staticContext.getQualifierForDescriptor(descriptor.getOriginal());
return staticContext.getQualifierForDescriptor(descriptor);
}
@NotNull
@@ -31,7 +31,6 @@ import java.util.Set;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getAllNonNativeNamespaceDescriptors;
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getAllClassesDefinedInNamespace;
import static org.jetbrains.k2js.translate.utils.NamespaceSortingUtils.sortNamespacesUsingQualificationOrder;
/**
* @author Pavel Talanov
@@ -51,7 +50,7 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator {
private NamespaceDeclarationTranslator(@NotNull List<NamespaceDescriptor> namespaceDescriptors,
@NotNull TranslationContext context) {
super(context);
this.namespaceDescriptors = sortNamespacesUsingQualificationOrder(namespaceDescriptors);
this.namespaceDescriptors = namespaceDescriptors;
this.classDeclarationTranslator = new ClassDeclarationTranslator(getAllClasses(), context);
}
@@ -91,7 +90,7 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator {
@NotNull
private List<NamespaceTranslator> getTranslatorsForNonEmptyNamespaces() {
List<NamespaceTranslator> namespaceTranslators = Lists.newArrayList();
for (NamespaceDescriptor descriptor : namespaceDescriptors) {
for (NamespaceDescriptor descriptor : filterTopLevelNamespaces(namespaceDescriptors)) {
if (!DescriptorUtils.isNamespaceEmpty(descriptor)) {
namespaceTranslators.add(new NamespaceTranslator(descriptor, classDeclarationTranslator, context()));
}
@@ -103,7 +102,7 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator {
private static List<JsStatement> declarationStatements(@NotNull List<NamespaceTranslator> namespaceTranslators) {
List<JsStatement> result = Lists.newArrayList();
for (NamespaceTranslator translator : namespaceTranslators) {
result.add(translator.getDeclarationStatement());
result.add(translator.getDeclarationAsVar());
}
return result;
}
@@ -116,4 +115,15 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator {
}
return result;
}
@NotNull
private static List<NamespaceDescriptor> filterTopLevelNamespaces(@NotNull List<NamespaceDescriptor> namespaceDescriptors) {
List<NamespaceDescriptor> result = Lists.newArrayList();
for (NamespaceDescriptor descriptor : namespaceDescriptors) {
if (DescriptorUtils.isTopLevelNamespace(descriptor)) {
result.add(descriptor);
}
}
return result;
}
}
@@ -64,25 +64,35 @@ public final class NamespaceTranslator extends AbstractTranslator {
}
@NotNull
private JsInvocation namespaceCreateMethodInvocation() {
return AstUtil.newInvocation(context().namer().namespaceCreationMethodReference());
public JsStatement getDeclarationAsVar() {
return newVar(namespaceName, getNamespaceDeclaration());
}
@NotNull
public JsStatement getDeclarationStatement() {
public JsPropertyInitializer getDeclarationAsInitializer() {
return new JsPropertyInitializer(namespaceName.makeRef(), getNamespaceDeclaration());
}
@NotNull
private JsInvocation getNamespaceDeclaration() {
JsInvocation namespaceDeclaration = namespaceCreateMethodInvocation();
namespaceDeclaration.getArguments().add(translateNamespaceMemberDeclarations());
namespaceDeclaration.getArguments().add(getClassesAndNestedNamespaces());
return newVar(namespaceName, namespaceDeclaration);
return namespaceDeclaration;
}
@NotNull
private JsInvocation namespaceCreateMethodInvocation() {
return AstUtil.newInvocation(context().namer().namespaceCreationMethodReference());
}
@NotNull
private JsObjectLiteral getClassesAndNestedNamespaces() {
JsObjectLiteral classesAndNestedNamespaces = new JsObjectLiteral();
classesAndNestedNamespaces.getPropertyInitializers()
.addAll(getClassesDefined());
.addAll(getClassesDefined());
classesAndNestedNamespaces.getPropertyInitializers()
.addAll(getNestedNamespaceDeclarations());
.addAll(getNestedNamespaceDeclarations());
return classesAndNestedNamespaces;
}
@@ -96,8 +106,8 @@ public final class NamespaceTranslator extends AbstractTranslator {
List<JsPropertyInitializer> result = Lists.newArrayList();
List<NamespaceDescriptor> nestedNamespaces = DescriptorUtils.getNestedNamespaces(descriptor);
for (NamespaceDescriptor nestedNamespace : nestedNamespaces) {
JsName nameForDescriptor = context().getNameForDescriptor(nestedNamespace);
result.add(new JsPropertyInitializer(nameForDescriptor.makeRef(), nameForDescriptor.makeRef()));
NamespaceTranslator nestedNamespaceTranslator = new NamespaceTranslator(nestedNamespace, classDeclarationTranslator, context());
result.add(nestedNamespaceTranslator.getDeclarationAsInitializer());
}
return result;
}
@@ -18,13 +18,14 @@ package org.jetbrains.k2js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.k2js.translate.context.TranslationContext;
import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getNotNullSimpleNameSelector;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelector;
@@ -58,7 +59,7 @@ public final class QualifiedExpressionTranslator {
}
@NotNull
private static JsExpression dispatchToCorrectTranslator(@NotNull JsExpression receiver,
private static JsExpression dispatchToCorrectTranslator(@Nullable JsExpression receiver,
@NotNull JetExpression selector,
@NotNull CallType callType,
@NotNull TranslationContext context) {
@@ -76,10 +77,31 @@ public final class QualifiedExpressionTranslator {
throw new AssertionError("Unexpected qualified expression: " + selector.getText());
}
//TODO: if has duplications
@NotNull
@Nullable
private static JsExpression translateReceiver(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
return translateAsExpression(expression.getReceiverExpression(), context);
JetExpression receiverExpression = expression.getReceiverExpression();
if (isFullQualifierForExpression(receiverExpression, context)) {
return null;
}
return translateAsExpression(receiverExpression, context);
}
//TODO: prove correctness
private static boolean isFullQualifierForExpression(@Nullable JetExpression receiverExpression, @NotNull TranslationContext context) {
if (receiverExpression == null) {
return false;
}
if (receiverExpression instanceof JetReferenceExpression) {
DeclarationDescriptor descriptorForReferenceExpression =
getDescriptorForReferenceExpression(context.bindingContext(), (JetReferenceExpression)receiverExpression);
if (descriptorForReferenceExpression instanceof NamespaceDescriptor) {
return true;
}
}
if (receiverExpression instanceof JetQualifiedExpression) {
return isFullQualifierForExpression(((JetQualifiedExpression)receiverExpression).getSelectorExpression(), context);
}
return false;
}
}
@@ -66,8 +66,8 @@ public final class DescriptorUtils {
@NotNull String name) {
Set<FunctionDescriptor> functionDescriptors = scope.getFunctions(name);
assert functionDescriptors.size() == 1 :
"In scope " + scope + " supposed to be exactly one " + name + " function.\n" +
"Found: " + functionDescriptors.size();
"In scope " + scope + " supposed to be exactly one " + name + " function.\n" +
"Found: " + functionDescriptors.size();
//noinspection LoopStatementThatDoesntLoop
for (FunctionDescriptor descriptor : functionDescriptors) {
return descriptor;
@@ -84,7 +84,7 @@ public final class DescriptorUtils {
Set<VariableDescriptor> variables = scope.getProperties(name);
assert variables.size() == 1 : "Actual size: " + variables.size();
VariableDescriptor variable = variables.iterator().next();
PropertyDescriptor descriptor = (PropertyDescriptor) variable;
PropertyDescriptor descriptor = (PropertyDescriptor)variable;
assert descriptor != null : "Must have a descriptor.";
return descriptor;
}
@@ -120,15 +120,15 @@ public final class DescriptorUtils {
@NotNull
public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
DeclarationDescriptor superClassDescriptor =
type.getConstructor().getDeclarationDescriptor();
type.getConstructor().getDeclarationDescriptor();
assert superClassDescriptor instanceof ClassDescriptor
: "Superclass descriptor of a type should be of type ClassDescriptor";
return (ClassDescriptor) superClassDescriptor;
: "Superclass descriptor of a type should be of type ClassDescriptor";
return (ClassDescriptor)superClassDescriptor;
}
@NotNull
public static VariableDescriptor getVariableDescriptorForVariableAsFunction
(@NotNull VariableAsFunctionDescriptor descriptor) {
(@NotNull VariableAsFunctionDescriptor descriptor) {
VariableDescriptor functionVariable = descriptor.getVariableDescriptor();
assert functionVariable != null;
return functionVariable;
@@ -171,9 +171,9 @@ public final class DescriptorUtils {
@NotNull
public static DeclarationDescriptor getDeclarationDescriptorForReceiver
(@NotNull ReceiverDescriptor receiverParameter) {
(@NotNull ReceiverDescriptor receiverParameter) {
DeclarationDescriptor declarationDescriptor =
receiverParameter.getType().getConstructor().getDeclarationDescriptor();
receiverParameter.getType().getConstructor().getDeclarationDescriptor();
//TODO: WHY assert?
assert declarationDescriptor != null;
return declarationDescriptor.getOriginal();
@@ -194,7 +194,7 @@ public final class DescriptorUtils {
DeclarationDescriptor containing = descriptor.getContainingDeclaration();
while (containing != null) {
if (containing instanceof ClassDescriptor) {
return (ClassDescriptor) containing;
return (ClassDescriptor)containing;
}
containing = containing.getContainingDeclaration();
}
@@ -206,7 +206,7 @@ public final class DescriptorUtils {
List<ClassDescriptor> classDescriptors = Lists.newArrayList();
for (DeclarationDescriptor descriptor : getContainedDescriptorsWhichAreNotPredefined(namespaceDescriptor)) {
if (descriptor instanceof ClassDescriptor) {
classDescriptors.add((ClassDescriptor) descriptor);
classDescriptors.add((ClassDescriptor)descriptor);
}
}
return classDescriptors;
@@ -217,7 +217,7 @@ public final class DescriptorUtils {
List<NamespaceDescriptor> result = Lists.newArrayList();
for (DeclarationDescriptor descriptor : getContainedDescriptorsWhichAreNotPredefined(namespaceDescriptor)) {
if (descriptor instanceof NamespaceDescriptor) {
result.add((NamespaceDescriptor) descriptor);
result.add((NamespaceDescriptor)descriptor);
}
}
return result;
@@ -235,21 +235,18 @@ public final class DescriptorUtils {
}
}
//TODO:?
// @NotNull
// public static FunctionDescriptor getOverriddenOrThis(@NotNull FunctionDescriptor functionDescriptor) {
// FunctionDescriptor overriddenDescriptor = getOverriddenDescriptor(functionDescriptor);
// if (overriddenDescriptor != null) {
// return overriddenDescriptor;
// }
// else {
// return functionDescriptor;
// }
// }
public static boolean isTopLevelNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
NamespaceDescriptorParent containingDeclaration = namespaceDescriptor.getContainingDeclaration();
boolean containedInModule = !(containingDeclaration instanceof NamespaceDescriptor);
if (containedInModule) {
return true;
}
//TODO
return containingDeclaration.getName().equals("<root>");
}
@NotNull
public static List<DeclarationDescriptor> getContainedDescriptorsWhichAreNotPredefined
(@NotNull NamespaceDescriptor namespace) {
public static List<DeclarationDescriptor> getContainedDescriptorsWhichAreNotPredefined(@NotNull NamespaceDescriptor namespace) {
List<DeclarationDescriptor> result = Lists.newArrayList();
for (DeclarationDescriptor descriptor : namespace.getMemberScope().getAllDescriptors()) {
if (!AnnotationsUtils.isPredefinedObject(descriptor)) {
@@ -264,7 +261,7 @@ public final class DescriptorUtils {
List<DeclarationDescriptor> containedDescriptors = getContainedDescriptorsWhichAreNotPredefined(namespace);
for (DeclarationDescriptor descriptor : containedDescriptors) {
if (descriptor instanceof NamespaceDescriptor) {
if (!isNamespaceEmpty((NamespaceDescriptor) descriptor)) {
if (!isNamespaceEmpty((NamespaceDescriptor)descriptor)) {
return false;
}
}
@@ -282,7 +279,7 @@ public final class DescriptorUtils {
while (!current.getName().equals("<root>")) {
result.add(current);
if (current.getContainingDeclaration() instanceof NamespaceDescriptor) {
current = (NamespaceDescriptor) current.getContainingDeclaration();
current = (NamespaceDescriptor)current.getContainingDeclaration();
assert current != null;
}
else {
@@ -1,54 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.translate.utils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptorParent;
import java.util.List;
/**
* @author Pavel Talanov
*/
public final class NamespaceSortingUtils {
private NamespaceSortingUtils() {
}
@NotNull
public static List<NamespaceDescriptor> sortNamespacesUsingQualificationOrder
(@NotNull List<NamespaceDescriptor> namespaceDescriptors) {
PartiallyOrderedSet<NamespaceDescriptor> namespaceDescriptorPartiallyOrderedSet
= new PartiallyOrderedSet<NamespaceDescriptor>(namespaceDescriptors, qualificationOrder());
return namespaceDescriptorPartiallyOrderedSet.partiallySortedElements();
}
@NotNull
private static PartiallyOrderedSet.Order<NamespaceDescriptor> qualificationOrder() {
return new PartiallyOrderedSet.Order<NamespaceDescriptor>() {
@Override
public boolean firstDependsOnSecond(@NotNull NamespaceDescriptor first, @NotNull NamespaceDescriptor second) {
NamespaceDescriptorParent containingDeclaration = first.getContainingDeclaration();
if (containingDeclaration == null) {
return false;
}
return containingDeclaration.equals(second);
}
};
}
}
@@ -0,0 +1,5 @@
package a.foo
import b.foo.*
fun box() = (A().tadada(A()))
@@ -0,0 +1,5 @@
package b.foo
class A() {
fun tadada(a : A) = true
}
@@ -0,0 +1,3 @@
package a.foo
fun box() = (b.foo.f() == 1)
@@ -0,0 +1,3 @@
package b.foo
fun f() = 1
@@ -0,0 +1,5 @@
package a.foo
import b.foo.f
fun box() = (f() == 1)
@@ -0,0 +1,3 @@
package b.foo
fun f() = 1
@@ -0,0 +1,7 @@
package foo1.foo2.foo3.foo5.foo6.foo7.foo8
fun box() = A().doBox()
class A() {
fun doBox() = true
}