Skip to content

Fix #11185: cache pretyped argument with adaptation in FunProto #12171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2101,7 +2101,11 @@ trait Applications extends Compatibility {
else defn.FunctionOf(commonParamTypes, WildcardType)
overload.println(i"pretype arg $arg with expected type $commonFormal")
if (commonParamTypes.forall(isFullyDefined(_, ForceDegree.flipBottom)))
withMode(Mode.ImplicitsEnabled)(pt.typedArg(arg, commonFormal))
withMode(Mode.ImplicitsEnabled) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first glance this looks too simplistic. We do a complicated dance not to overcommit by caching arguments that can be passed to several different expected types. How can we be sure that we can simply cache in this case? Maybe we can, but we'd need a detailed comment why.

Copy link
Contributor Author

@liufengyun liufengyun Apr 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, a comment is deserved here. Currently I see the rationale is this: the expected type for pretyping here come from all the overloading candidates and they (commandParamTypes) are all fully defined.

I just checked: it does not work with master anymore. I think #12138 is to blame.

I rebased against master, it seems to work.

// We can cache the adapted argument here because the expected type
// is a common type shared by all overloading candidates.
pt.cacheArg(arg, pt.typedArg(arg, commonFormal))
}
}
recur(altFormals.map(_.tail), args1)
case _ =>
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ object ProtoTypes {
if (t == null) NoType else t.tpe
}

/** Cache the typed argument */
def cacheArg(arg: untpd.Tree, targ: Tree) =
state.typedArg = state.typedArg.updated(arg, targ)

/** The same proto-type but with all arguments combined in a single tuple */
def tupledDual: FunProto = state.tupledDual match {
case pt: FunProto =>
Expand Down
14 changes: 14 additions & 0 deletions tests/pos/i11185.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Test:
def foo(a: Int, b: Int) = a + b

Map(1 -> 2).map(foo _)
Copy link
Contributor

@Jasper-M Jasper-M Apr 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a random thought, but if the collections ever get rewritten again, map might not be overloaded anymore. In which case this test no longer does what was intended.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'll add another test with overloading.

Map(1 -> 2).map(foo)

class Test2:
def foo(a: Int, b: Int) = a + b

def bar(f: ((Int, Int)) => Int) = "ok"
def bar(f: ((Int, Int)) => String)(using Int) = "ok"

bar(foo)
bar(foo _)