REPL overload resolution ambiguity
Fix overload resolution ambiguity in REPL. Note, resolution for functions declared in script is very different from regular programs: in scripts function declared later wins. See functionOverloadResolutionAnyBeatsString for example. #KT-2272 Fixed
This commit is contained in:
@@ -43,6 +43,7 @@ import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter;
|
|||||||
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
|
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
|
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
|
||||||
|
import org.jetbrains.jet.lang.resolve.ScriptHeaderResolver;
|
||||||
import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters;
|
import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters;
|
||||||
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
|
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
|
||||||
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
|
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
|
||||||
@@ -150,6 +151,8 @@ public class ReplInterpreter {
|
|||||||
|
|
||||||
injector.getTopDownAnalyzer().prepareForTheNextReplLine();
|
injector.getTopDownAnalyzer().prepareForTheNextReplLine();
|
||||||
|
|
||||||
|
psiFile.getScript().putUserData(ScriptHeaderResolver.PRIORITY_KEY, lineNumber);
|
||||||
|
|
||||||
ScriptDescriptor scriptDescriptor = doAnalyze(psiFile);
|
ScriptDescriptor scriptDescriptor = doAnalyze(psiFile);
|
||||||
|
|
||||||
Progress backendProgress = new Progress() {
|
Progress backendProgress = new Progress() {
|
||||||
|
|||||||
@@ -34,14 +34,17 @@ import java.util.List;
|
|||||||
public class ScriptDescriptor extends DeclarationDescriptorImpl {
|
public class ScriptDescriptor extends DeclarationDescriptorImpl {
|
||||||
private static final Name NAME = Name.special("<script>");
|
private static final Name NAME = Name.special("<script>");
|
||||||
|
|
||||||
|
private final int priority;
|
||||||
|
|
||||||
private JetType returnType;
|
private JetType returnType;
|
||||||
private List<ValueParameterDescriptor> valueParameters;
|
private List<ValueParameterDescriptor> valueParameters;
|
||||||
|
|
||||||
private final ScriptCodeDescriptor scriptCodeDescriptor = new ScriptCodeDescriptor(this);
|
private final ScriptCodeDescriptor scriptCodeDescriptor = new ScriptCodeDescriptor(this);
|
||||||
private final ReceiverDescriptor implicitReceiver = new ScriptReceiver(this);
|
private final ReceiverDescriptor implicitReceiver = new ScriptReceiver(this);
|
||||||
|
|
||||||
public ScriptDescriptor(@Nullable DeclarationDescriptor containingDeclaration) {
|
public ScriptDescriptor(@Nullable DeclarationDescriptor containingDeclaration, int priority) {
|
||||||
super(containingDeclaration, Collections.<AnnotationDescriptor>emptyList(), NAME);
|
super(containingDeclaration, Collections.<AnnotationDescriptor>emptyList(), NAME);
|
||||||
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(@NotNull JetType returnType) {
|
public void initialize(@NotNull JetType returnType) {
|
||||||
@@ -49,6 +52,10 @@ public class ScriptDescriptor extends DeclarationDescriptorImpl {
|
|||||||
scriptCodeDescriptor.initialize(implicitReceiver, valueParameters, returnType);
|
scriptCodeDescriptor.initialize(implicitReceiver, valueParameters, returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getPriority() {
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetType getReturnType() {
|
public JetType getReturnType() {
|
||||||
return returnType;
|
return returnType;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.jet.lang.resolve;
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.intellij.openapi.util.Key;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
@@ -50,6 +51,8 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
|||||||
*/
|
*/
|
||||||
public class ScriptHeaderResolver {
|
public class ScriptHeaderResolver {
|
||||||
|
|
||||||
|
public static final Key<Integer> PRIORITY_KEY = Key.create(JetScript.class.getName() + ".priority");
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private NamespaceFactory namespaceFactory;
|
private NamespaceFactory namespaceFactory;
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -118,7 +121,13 @@ public class ScriptHeaderResolver {
|
|||||||
|
|
||||||
public void processScriptHierarchy(@NotNull JetScript script, @NotNull JetScope outerScope) {
|
public void processScriptHierarchy(@NotNull JetScript script, @NotNull JetScope outerScope) {
|
||||||
NamespaceDescriptorImpl ns = namespaceFactory.createNamespaceDescriptorPathIfNeeded(FqName.ROOT);
|
NamespaceDescriptorImpl ns = namespaceFactory.createNamespaceDescriptorPathIfNeeded(FqName.ROOT);
|
||||||
ScriptDescriptor scriptDescriptor = new ScriptDescriptor(ns);
|
|
||||||
|
Integer priority = script.getUserData(PRIORITY_KEY);
|
||||||
|
if (priority == null) {
|
||||||
|
priority = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptDescriptor scriptDescriptor = new ScriptDescriptor(ns, priority);
|
||||||
//WriteThroughScope scriptScope = new WriteThroughScope(
|
//WriteThroughScope scriptScope = new WriteThroughScope(
|
||||||
// outerScope, ns.getMemberScope(), new TraceBasedRedeclarationHandler(trace));
|
// outerScope, ns.getMemberScope(), new TraceBasedRedeclarationHandler(trace));
|
||||||
WritableScopeImpl scriptScope = new WritableScopeImpl(outerScope, scriptDescriptor, RedeclarationHandler.DO_NOTHING, "script");
|
WritableScopeImpl scriptScope = new WritableScopeImpl(outerScope, scriptDescriptor, RedeclarationHandler.DO_NOTHING, "script");
|
||||||
|
|||||||
+10
@@ -21,6 +21,7 @@ import gnu.trove.TObjectHashingStrategy;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.OverridingUtil;
|
import org.jetbrains.jet.lang.resolve.OverridingUtil;
|
||||||
@@ -80,6 +81,15 @@ public class OverloadingConflictResolver {
|
|||||||
* Int < Short < Byte
|
* Int < Short < Byte
|
||||||
*/
|
*/
|
||||||
private <Descriptor extends CallableDescriptor> boolean moreSpecific(Descriptor f, Descriptor g, boolean discriminateGenericDescriptors) {
|
private <Descriptor extends CallableDescriptor> boolean moreSpecific(Descriptor f, Descriptor g, boolean discriminateGenericDescriptors) {
|
||||||
|
if (f.getContainingDeclaration() instanceof ScriptDescriptor && g.getContainingDeclaration() instanceof ScriptDescriptor) {
|
||||||
|
ScriptDescriptor fs = (ScriptDescriptor) f.getContainingDeclaration();
|
||||||
|
ScriptDescriptor gs = (ScriptDescriptor) g.getContainingDeclaration();
|
||||||
|
|
||||||
|
if (fs.getPriority() != gs.getPriority()) {
|
||||||
|
return fs.getPriority() > gs.getPriority();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (discriminateGenericDescriptors && !isGeneric(f) && isGeneric(g)) return true;
|
if (discriminateGenericDescriptors && !isGeneric(f) && isGeneric(g)) return true;
|
||||||
if (OverridingUtil.overrides(f, g)) return true;
|
if (OverridingUtil.overrides(f, g)) return true;
|
||||||
if (OverridingUtil.overrides(g, f)) return false;
|
if (OverridingUtil.overrides(g, f)) return false;
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
>>> fun foo() = 10
|
||||||
|
null
|
||||||
|
>>> fun foo() = 11
|
||||||
|
null
|
||||||
|
>>> foo()
|
||||||
|
11
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
>>> fun foo(s: String) = "string"
|
||||||
|
null
|
||||||
|
>>> fun foo(a: Any) = "any"
|
||||||
|
null
|
||||||
|
>>> foo("a")
|
||||||
|
any
|
||||||
@@ -92,6 +92,16 @@ public class ReplInterpreterTest {
|
|||||||
testFile("twoClosures.repl");
|
testFile("twoClosures.repl");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void functionOverloadResolutionAnyBeatsString() {
|
||||||
|
testFile("functionOverloadResolutionAnyBeatsString.repl");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void functionOverloadResolution() {
|
||||||
|
testFile("functionOverloadResolution.repl");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void empty() {
|
public void empty() {
|
||||||
testFile("empty.repl");
|
testFile("empty.repl");
|
||||||
|
|||||||
Reference in New Issue
Block a user