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.BindingContext;
|
||||
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.TraceBasedRedeclarationHandler;
|
||||
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
|
||||
@@ -150,6 +151,8 @@ public class ReplInterpreter {
|
||||
|
||||
injector.getTopDownAnalyzer().prepareForTheNextReplLine();
|
||||
|
||||
psiFile.getScript().putUserData(ScriptHeaderResolver.PRIORITY_KEY, lineNumber);
|
||||
|
||||
ScriptDescriptor scriptDescriptor = doAnalyze(psiFile);
|
||||
|
||||
Progress backendProgress = new Progress() {
|
||||
|
||||
@@ -34,14 +34,17 @@ import java.util.List;
|
||||
public class ScriptDescriptor extends DeclarationDescriptorImpl {
|
||||
private static final Name NAME = Name.special("<script>");
|
||||
|
||||
private final int priority;
|
||||
|
||||
private JetType returnType;
|
||||
private List<ValueParameterDescriptor> valueParameters;
|
||||
|
||||
private final ScriptCodeDescriptor scriptCodeDescriptor = new ScriptCodeDescriptor(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);
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public void initialize(@NotNull JetType returnType) {
|
||||
@@ -49,6 +52,10 @@ public class ScriptDescriptor extends DeclarationDescriptorImpl {
|
||||
scriptCodeDescriptor.initialize(implicitReceiver, valueParameters, returnType);
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetType getReturnType() {
|
||||
return returnType;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
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 static final Key<Integer> PRIORITY_KEY = Key.create(JetScript.class.getName() + ".priority");
|
||||
|
||||
@NotNull
|
||||
private NamespaceFactory namespaceFactory;
|
||||
@NotNull
|
||||
@@ -118,7 +121,13 @@ public class ScriptHeaderResolver {
|
||||
|
||||
public void processScriptHierarchy(@NotNull JetScript script, @NotNull JetScope outerScope) {
|
||||
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(
|
||||
// outerScope, ns.getMemberScope(), new TraceBasedRedeclarationHandler(trace));
|
||||
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.Nullable;
|
||||
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.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.OverridingUtil;
|
||||
@@ -80,6 +81,15 @@ public class OverloadingConflictResolver {
|
||||
* Int < Short < Byte
|
||||
*/
|
||||
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 (OverridingUtil.overrides(f, g)) return true;
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void functionOverloadResolutionAnyBeatsString() {
|
||||
testFile("functionOverloadResolutionAnyBeatsString.repl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void functionOverloadResolution() {
|
||||
testFile("functionOverloadResolution.repl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void empty() {
|
||||
testFile("empty.repl");
|
||||
|
||||
Reference in New Issue
Block a user