KT-328 completion //Local function in function literals cause exceptions
This commit is contained in:
@@ -364,12 +364,12 @@ public class JetFlowInformationProvider {
|
|||||||
JetNamedDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
|
JetNamedDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
|
||||||
DeclarationDescriptor declarationDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, parentDeclaration);
|
DeclarationDescriptor declarationDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, parentDeclaration);
|
||||||
assert declarationDescriptor != null;
|
assert declarationDescriptor != null;
|
||||||
ClassDescriptor variableClass = DescriptorUtils.getParentOfType(variableDescriptor, ClassDescriptor.class);
|
DeclarationDescriptor containingDeclaration = variableDescriptor.getContainingDeclaration();
|
||||||
if (variableClass == null || !DescriptorUtils.isAncestor(variableClass, declarationDescriptor, false)) {
|
if ((containingDeclaration instanceof ClassDescriptor) && DescriptorUtils.isAncestor(containingDeclaration, declarationDescriptor, false)) {
|
||||||
trace.report(Errors.INACCESSIBLE_BACKING_FIELD.on(element));
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
trace.report(Errors.INACCESSIBLE_BACKING_FIELD.on(element));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isBackingFieldReference(@Nullable JetElement element, boolean[] error, boolean reportError) {
|
private boolean isBackingFieldReference(@Nullable JetElement element, boolean[] error, boolean reportError) {
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ public class BodyResolver {
|
|||||||
resolveSecondaryConstructorBodies();
|
resolveSecondaryConstructorBodies();
|
||||||
resolveFunctionBodies();
|
resolveFunctionBodies();
|
||||||
|
|
||||||
computeDeferredTypes();
|
if (!context.isDeclaredLocally()) {
|
||||||
|
computeDeferredTypes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resolveDelegationSpecifierLists() {
|
private void resolveDelegationSpecifierLists() {
|
||||||
@@ -364,6 +366,8 @@ public class BodyResolver {
|
|||||||
final PropertyDescriptor propertyDescriptor = this.context.getProperties().get(property);
|
final PropertyDescriptor propertyDescriptor = this.context.getProperties().get(property);
|
||||||
assert propertyDescriptor != null;
|
assert propertyDescriptor != null;
|
||||||
|
|
||||||
|
computeDeferredType(propertyDescriptor.getReturnType());
|
||||||
|
|
||||||
JetExpression initializer = property.getInitializer();
|
JetExpression initializer = property.getInitializer();
|
||||||
if (initializer != null) {
|
if (initializer != null) {
|
||||||
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
|
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
|
||||||
@@ -385,6 +389,9 @@ public class BodyResolver {
|
|||||||
if (processed.contains(property)) continue;
|
if (processed.contains(property)) continue;
|
||||||
|
|
||||||
final PropertyDescriptor propertyDescriptor = entry.getValue();
|
final PropertyDescriptor propertyDescriptor = entry.getValue();
|
||||||
|
|
||||||
|
computeDeferredType(propertyDescriptor.getReturnType());
|
||||||
|
|
||||||
JetScope declaringScope = this.context.getDeclaringScopes().get(property);
|
JetScope declaringScope = this.context.getDeclaringScopes().get(property);
|
||||||
|
|
||||||
JetExpression initializer = property.getInitializer();
|
JetExpression initializer = property.getInitializer();
|
||||||
@@ -395,7 +402,7 @@ public class BodyResolver {
|
|||||||
resolvePropertyAccessors(property, propertyDescriptor);
|
resolvePropertyAccessors(property, propertyDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetScope makeScopeForPropertyAccessor(@NotNull JetPropertyAccessor accessor, PropertyDescriptor propertyDescriptor) {
|
private JetScope makeScopeForPropertyAccessor(@NotNull JetPropertyAccessor accessor, PropertyDescriptor propertyDescriptor) {
|
||||||
JetScope declaringScope = context.getDeclaringScopes().get(accessor);
|
JetScope declaringScope = context.getDeclaringScopes().get(accessor);
|
||||||
|
|
||||||
@@ -462,18 +469,8 @@ public class BodyResolver {
|
|||||||
for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : this.context.getFunctions().entrySet()) {
|
for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : this.context.getFunctions().entrySet()) {
|
||||||
JetNamedFunction declaration = entry.getKey();
|
JetNamedFunction declaration = entry.getKey();
|
||||||
FunctionDescriptor descriptor = entry.getValue();
|
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();
|
computeDeferredType(descriptor.getReturnType());
|
||||||
returnType.getActualType();
|
|
||||||
}
|
|
||||||
|
|
||||||
JetScope declaringScope = this.context.getDeclaringScopes().get(declaration);
|
JetScope declaringScope = this.context.getDeclaringScopes().get(declaration);
|
||||||
assert declaringScope != null;
|
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() {
|
private void computeDeferredTypes() {
|
||||||
Collection<Box<DeferredType>> deferredTypes = context.getTrace().getKeys(DEFERRED_TYPE);
|
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 {
|
public class ControlFlowAnalyzer {
|
||||||
private TopDownAnalysisContext context;
|
private TopDownAnalysisContext context;
|
||||||
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
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.context = context;
|
||||||
this.flowDataTraceFactory = flowDataTraceFactory;
|
this.flowDataTraceFactory = flowDataTraceFactory;
|
||||||
this.processLocalDeclaration = processLocalDeclaration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void process() {
|
public void process() {
|
||||||
@@ -58,7 +56,7 @@ public class ControlFlowAnalyzer {
|
|||||||
|
|
||||||
private void checkClassOrObject(JetClassOrObject klass) {
|
private void checkClassOrObject(JetClassOrObject klass) {
|
||||||
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) klass, (JetExpression) klass, flowDataTraceFactory, context.getTrace());
|
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) {
|
private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
|
||||||
@@ -80,7 +78,7 @@ public class ControlFlowAnalyzer {
|
|||||||
|
|
||||||
flowInformationProvider.checkDefiniteReturn(function, expectedReturnType);
|
flowInformationProvider.checkDefiniteReturn(function, expectedReturnType);
|
||||||
|
|
||||||
flowInformationProvider.markUninitializedVariables(function.asElement(), processLocalDeclaration);
|
flowInformationProvider.markUninitializedVariables(function.asElement(), context.isDeclaredLocally());
|
||||||
|
|
||||||
flowInformationProvider.markUnusedVariables(function.asElement());
|
flowInformationProvider.markUnusedVariables(function.asElement());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,13 +42,15 @@ import java.util.Set;
|
|||||||
|
|
||||||
private StringBuilder debugOutput;
|
private StringBuilder debugOutput;
|
||||||
private boolean analyzingBootstrapLibrary = false;
|
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.trace = new ObservableBindingTrace(trace);
|
||||||
this.semanticServices = semanticServices;
|
this.semanticServices = semanticServices;
|
||||||
this.descriptorResolver = semanticServices.getClassDescriptorResolver(trace);
|
this.descriptorResolver = semanticServices.getClassDescriptorResolver(trace);
|
||||||
this.analyzeCompletely = analyzeCompletely;
|
this.analyzeCompletely = analyzeCompletely;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
|
this.declaredLocally = declaredLocally;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void debug(Object message) {
|
public void debug(Object message) {
|
||||||
@@ -138,4 +140,8 @@ import java.util.Set;
|
|||||||
public Configuration getConfiguration() {
|
public Configuration getConfiguration() {
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDeclaredLocally() {
|
||||||
|
return declaredLocally;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ public class TopDownAnalyzer {
|
|||||||
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory,
|
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory,
|
||||||
@NotNull Configuration configuration,
|
@NotNull Configuration configuration,
|
||||||
boolean declaredLocally) {
|
boolean declaredLocally) {
|
||||||
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, analyzeCompletely, configuration);
|
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, analyzeCompletely, configuration, declaredLocally);
|
||||||
doProcess(context, outerScope, owner, declarations, flowDataTraceFactory, declaredLocally);
|
doProcess(context, outerScope, owner, declarations, flowDataTraceFactory);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,8 +56,7 @@ public class TopDownAnalyzer {
|
|||||||
TopDownAnalysisContext context, JetScope outerScope,
|
TopDownAnalysisContext context, JetScope outerScope,
|
||||||
NamespaceLike owner,
|
NamespaceLike owner,
|
||||||
Collection<? extends JetDeclaration> declarations,
|
Collection<? extends JetDeclaration> declarations,
|
||||||
JetControlFlowDataTraceFactory flowDataTraceFactory,
|
JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||||
boolean processLocalDeclaration) {
|
|
||||||
// context.enableDebugOutput();
|
// context.enableDebugOutput();
|
||||||
context.debug("Enter");
|
context.debug("Enter");
|
||||||
|
|
||||||
@@ -69,7 +68,7 @@ public class TopDownAnalyzer {
|
|||||||
new OverloadResolver(context).process();
|
new OverloadResolver(context).process();
|
||||||
if (!context.analyzingBootstrapLibrary()) {
|
if (!context.analyzingBootstrapLibrary()) {
|
||||||
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
||||||
new ControlFlowAnalyzer(context, flowDataTraceFactory, processLocalDeclaration).process();
|
new ControlFlowAnalyzer(context, flowDataTraceFactory).process();
|
||||||
new DeclarationsChecker(context).process();
|
new DeclarationsChecker(context).process();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,13 +92,13 @@ public class TopDownAnalyzer {
|
|||||||
@NotNull JetSemanticServices semanticServices,
|
@NotNull JetSemanticServices semanticServices,
|
||||||
@NotNull BindingTrace trace,
|
@NotNull BindingTrace trace,
|
||||||
@NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) {
|
@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.getNamespaceScopes().put(namespace, standardLibraryNamespace.getMemberScope());
|
||||||
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
|
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
|
||||||
context.getDeclaringScopes().put(namespace, outerScope);
|
context.getDeclaringScopes().put(namespace, outerScope);
|
||||||
context.setAnalyzingBootstrapLibrary(true);
|
context.setAnalyzingBootstrapLibrary(true);
|
||||||
|
|
||||||
doProcess(context, outerScope, standardLibraryNamespace, namespace.getDeclarations(), JetControlFlowDataTraceFactory.EMPTY, false);
|
doProcess(context, outerScope, standardLibraryNamespace, namespace.getDeclarations(), JetControlFlowDataTraceFactory.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void processObject(
|
public static void processObject(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace a {
|
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 {
|
namespace b {
|
||||||
@@ -39,4 +39,4 @@ namespace ok {
|
|||||||
|
|
||||||
fun bar() = foo()
|
fun bar() = foo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// JET-81 Assertion fails when processing self-referring anonymous objects
|
// JET-81 Assertion fails when processing self-referring anonymous objects
|
||||||
|
|
||||||
val y = object {
|
val y = object {
|
||||||
val a = y;
|
val a = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>y<!>;
|
||||||
}
|
}
|
||||||
|
|
||||||
val z = y.a;
|
val z = y.a;
|
||||||
@@ -19,4 +19,4 @@ val a = object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val b = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>a<!>.x
|
val b = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>a<!>.x
|
||||||
val c = a.y
|
val c = a.y
|
||||||
@@ -1,3 +1,28 @@
|
|||||||
fun bar() = {
|
//KT-328 Local function in function literals cause exceptions
|
||||||
<!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>bar()<!>
|
|
||||||
|
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 {
|
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 {
|
namespace b {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// JET-81 Assertion fails when processing self-referring anonymous objects
|
// JET-81 Assertion fails when processing self-referring anonymous objects
|
||||||
|
|
||||||
val y = object {
|
val y = object {
|
||||||
val a = y;
|
val a = <error>y</error>
|
||||||
}
|
}
|
||||||
|
|
||||||
val z = y.a;
|
val z = y.a;
|
||||||
|
|||||||
Reference in New Issue
Block a user