KT-328 completion //Local function in function literals cause exceptions

This commit is contained in:
svtk
2011-12-09 17:37:38 +04:00
parent 4d303b0225
commit 63d74d41af
12 changed files with 79 additions and 50 deletions
@@ -364,12 +364,12 @@ public class JetFlowInformationProvider {
JetNamedDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
DeclarationDescriptor declarationDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, parentDeclaration);
assert declarationDescriptor != null;
ClassDescriptor variableClass = DescriptorUtils.getParentOfType(variableDescriptor, ClassDescriptor.class);
if (variableClass == null || !DescriptorUtils.isAncestor(variableClass, declarationDescriptor, false)) {
trace.report(Errors.INACCESSIBLE_BACKING_FIELD.on(element));
return true;
DeclarationDescriptor containingDeclaration = variableDescriptor.getContainingDeclaration();
if ((containingDeclaration instanceof ClassDescriptor) && DescriptorUtils.isAncestor(containingDeclaration, declarationDescriptor, false)) {
return false;
}
return false;
trace.report(Errors.INACCESSIBLE_BACKING_FIELD.on(element));
return true;
}
private boolean isBackingFieldReference(@Nullable JetElement element, boolean[] error, boolean reportError) {
@@ -54,7 +54,9 @@ public class BodyResolver {
resolveSecondaryConstructorBodies();
resolveFunctionBodies();
computeDeferredTypes();
if (!context.isDeclaredLocally()) {
computeDeferredTypes();
}
}
private void resolveDelegationSpecifierLists() {
@@ -364,6 +366,8 @@ public class BodyResolver {
final PropertyDescriptor propertyDescriptor = this.context.getProperties().get(property);
assert propertyDescriptor != null;
computeDeferredType(propertyDescriptor.getReturnType());
JetExpression initializer = property.getInitializer();
if (initializer != null) {
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
@@ -385,6 +389,9 @@ public class BodyResolver {
if (processed.contains(property)) continue;
final PropertyDescriptor propertyDescriptor = entry.getValue();
computeDeferredType(propertyDescriptor.getReturnType());
JetScope declaringScope = this.context.getDeclaringScopes().get(property);
JetExpression initializer = property.getInitializer();
@@ -395,7 +402,7 @@ public class BodyResolver {
resolvePropertyAccessors(property, propertyDescriptor);
}
}
private JetScope makeScopeForPropertyAccessor(@NotNull JetPropertyAccessor accessor, PropertyDescriptor propertyDescriptor) {
JetScope declaringScope = context.getDeclaringScopes().get(accessor);
@@ -462,18 +469,8 @@ public class BodyResolver {
for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : this.context.getFunctions().entrySet()) {
JetNamedFunction declaration = entry.getKey();
FunctionDescriptor descriptor = entry.getValue();
if (descriptor.getReturnType() instanceof DeferredType) {
// handle type inference loop: function body contains a closure that calls that function
//
// fun f() = { f() }
//
// function type resolution must be started before function body resolution
//
DeferredType returnType = (DeferredType) descriptor.getReturnType();
returnType.getActualType();
}
computeDeferredType(descriptor.getReturnType());
JetScope declaringScope = this.context.getDeclaringScopes().get(declaration);
assert declaringScope != null;
@@ -520,6 +517,19 @@ public class BodyResolver {
}
}
}
private static void computeDeferredType(JetType type) {
// handle type inference loop: function or property body contains a reference to itself
// fun f() = { f() }
// val x = x
// type resolution must be started before body resolution
if (type instanceof DeferredType) {
DeferredType deferredType = (DeferredType) type;
if (!deferredType.isComputed()) {
deferredType.getActualType();
}
}
}
private void computeDeferredTypes() {
Collection<Box<DeferredType>> deferredTypes = context.getTrace().getKeys(DEFERRED_TYPE);
@@ -19,12 +19,10 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
public class ControlFlowAnalyzer {
private TopDownAnalysisContext context;
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
private final boolean processLocalDeclaration;
public ControlFlowAnalyzer(TopDownAnalysisContext context, JetControlFlowDataTraceFactory flowDataTraceFactory, boolean processLocalDeclaration) {
public ControlFlowAnalyzer(TopDownAnalysisContext context, JetControlFlowDataTraceFactory flowDataTraceFactory) {
this.context = context;
this.flowDataTraceFactory = flowDataTraceFactory;
this.processLocalDeclaration = processLocalDeclaration;
}
public void process() {
@@ -58,7 +56,7 @@ public class ControlFlowAnalyzer {
private void checkClassOrObject(JetClassOrObject klass) {
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) klass, (JetExpression) klass, flowDataTraceFactory, context.getTrace());
flowInformationProvider.markUninitializedVariables((JetElement) klass, processLocalDeclaration);
flowInformationProvider.markUninitializedVariables((JetElement) klass, context.isDeclaredLocally());
}
private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
@@ -80,7 +78,7 @@ public class ControlFlowAnalyzer {
flowInformationProvider.checkDefiniteReturn(function, expectedReturnType);
flowInformationProvider.markUninitializedVariables(function.asElement(), processLocalDeclaration);
flowInformationProvider.markUninitializedVariables(function.asElement(), context.isDeclaredLocally());
flowInformationProvider.markUnusedVariables(function.asElement());
}
@@ -42,13 +42,15 @@ import java.util.Set;
private StringBuilder debugOutput;
private boolean analyzingBootstrapLibrary = false;
private boolean declaredLocally;
public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace, Predicate<PsiFile> analyzeCompletely, @NotNull Configuration configuration) {
public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace, Predicate<PsiFile> analyzeCompletely, @NotNull Configuration configuration, boolean declaredLocally) {
this.trace = new ObservableBindingTrace(trace);
this.semanticServices = semanticServices;
this.descriptorResolver = semanticServices.getClassDescriptorResolver(trace);
this.analyzeCompletely = analyzeCompletely;
this.configuration = configuration;
this.declaredLocally = declaredLocally;
}
public void debug(Object message) {
@@ -138,4 +140,8 @@ import java.util.Set;
public Configuration getConfiguration() {
return configuration;
}
public boolean isDeclaredLocally() {
return declaredLocally;
}
}
@@ -47,8 +47,8 @@ public class TopDownAnalyzer {
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory,
@NotNull Configuration configuration,
boolean declaredLocally) {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, analyzeCompletely, configuration);
doProcess(context, outerScope, owner, declarations, flowDataTraceFactory, declaredLocally);
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, analyzeCompletely, configuration, declaredLocally);
doProcess(context, outerScope, owner, declarations, flowDataTraceFactory);
}
@@ -56,8 +56,7 @@ public class TopDownAnalyzer {
TopDownAnalysisContext context, JetScope outerScope,
NamespaceLike owner,
Collection<? extends JetDeclaration> declarations,
JetControlFlowDataTraceFactory flowDataTraceFactory,
boolean processLocalDeclaration) {
JetControlFlowDataTraceFactory flowDataTraceFactory) {
// context.enableDebugOutput();
context.debug("Enter");
@@ -69,7 +68,7 @@ public class TopDownAnalyzer {
new OverloadResolver(context).process();
if (!context.analyzingBootstrapLibrary()) {
new BodyResolver(context).resolveBehaviorDeclarationBodies();
new ControlFlowAnalyzer(context, flowDataTraceFactory, processLocalDeclaration).process();
new ControlFlowAnalyzer(context, flowDataTraceFactory).process();
new DeclarationsChecker(context).process();
}
@@ -93,13 +92,13 @@ public class TopDownAnalyzer {
@NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace,
@NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, Predicates.<PsiFile>alwaysTrue(), Configuration.EMPTY);
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, Predicates.<PsiFile>alwaysTrue(), Configuration.EMPTY, false);
context.getNamespaceScopes().put(namespace, standardLibraryNamespace.getMemberScope());
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
context.getDeclaringScopes().put(namespace, outerScope);
context.setAnalyzingBootstrapLibrary(true);
doProcess(context, outerScope, standardLibraryNamespace, namespace.getDeclarations(), JetControlFlowDataTraceFactory.EMPTY, false);
doProcess(context, outerScope, standardLibraryNamespace, namespace.getDeclarations(), JetControlFlowDataTraceFactory.EMPTY);
}
public static void processObject(
@@ -1,7 +1,7 @@
namespace a {
val foo = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar()<!>
val foo = bar()
fun bar() = foo
fun bar() = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>foo<!>
}
namespace b {
@@ -39,4 +39,4 @@ namespace ok {
fun bar() = foo()
}
}
}
@@ -1,7 +1,7 @@
// JET-81 Assertion fails when processing self-referring anonymous objects
val y = object {
val a = y;
val a = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>y<!>;
}
val z = y.a;
@@ -19,4 +19,4 @@ val a = object {
}
val b = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>a<!>.x
val c = a.y
val c = a.y
@@ -1,3 +1,28 @@
fun bar() = {
<!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar()<!>
//KT-328 Local function in function literals cause exceptions
fun bar1() = {
<!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar1()<!>
}
fun bar2() = {
fun foo2() = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar2()<!>
}
//properties
//in a class
class A() {
val x = { <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>x<!> }
}
//in a namespace
val x = { <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>x<!> }
//KT-787 AssertionError on code 'val x = x'
val z = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>z<!>
//KT-329 Assertion failure on local function
fun block(f : fun() : Unit) = f()
fun bar3() = block{ <!UNRESOLVED_REFERENCE!>foo3<!>() // <-- missing closing curly bracket
fun foo3() = block{ <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar3()<!> }<!SYNTAX!><!>
@@ -1,3 +0,0 @@
fun bar() = {
fun foo() = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar()<!>
}
@@ -1,6 +0,0 @@
// http://youtrack.jetbrains.net/issue/KT-329
fun block(f : fun() : Unit) = f()
fun bar() = block{ <!UNRESOLVED_REFERENCE!>foo<!>() // <-- missing closing curly bracket
fun foo() = block{ <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar()<!> }<!SYNTAX!><!>
@@ -1,7 +1,7 @@
namespace a {
val foo = <error descr="[TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM] Type checking has run into a recursive problem">bar()</error>
val foo = bar()
fun bar() = foo
fun bar() = <error descr="[TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM] Type checking has run into a recursive problem">foo</error>
}
namespace b {
+1 -1
View File
@@ -1,7 +1,7 @@
// JET-81 Assertion fails when processing self-referring anonymous objects
val y = object {
val a = y;
val a = <error>y</error>
}
val z = y.a;