Skip to content
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

summonAll after importing givens from a function parameter causes compiler crash #19493

Closed
KuceraMartin opened this issue Jan 19, 2024 · 5 comments · Fixed by #20837
Closed

Comments

@KuceraMartin
Copy link
Contributor

Compiler version

3.4.0-RC2

Minimized code

import compiletime.summonAll
import deriving.Mirror

type Sc[X] = X
case class Row[T[_]](name: T[String])

class DialectTypeMappers:
  given String = ???

inline def metadata(dialect: DialectTypeMappers)(using m: Mirror.Of[Row[Sc]]): m.MirroredElemTypes =
  import dialect.given
  summonAll[m.MirroredElemTypes]

def f = metadata(???)

Output (click arrow to expand)

  unhandled exception while running MegaPhase{lambdaLift, elimStaticThis, countOuterAccesses} on /Users/martin/development/macro-test/main.scala

  An unhandled exception was thrown in the compiler.
  Please file a crash report here:
  https://github.com/lampepfl/dotty/issues/new/choose
  For non-enriched exceptions, compile with -Yno-enrich-error-messages.

     while compiling: /Users/martin/development/macro-test/main.scala
        during phase: MegaPhase{lambdaLift, elimStaticThis, countOuterAccesses}
                mode: Mode(ImplicitsEnabled)
     library version: version 2.13.12
    compiler version: version 3.4.0-RC2
            settings: -classpath /Users/martin/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.4.0-RC2/scala3-library_3-3.4.0-RC2.jar:/Users/martin/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar -d /Users/martin/development/macro-test/.scala-build/macro-test_3200b05eac-d141fe35e1/classes/main -java-output-version 17 -sourceroot /Users/martin/development/macro-test

Exception in thread "main" java.lang.IllegalArgumentException: Could not find proxy for dialect: DialectTypeMappers in [parameter dialect, method metadata, the top-level definitions in package <empty>, package <empty>, package <root>], encl = method f, owners = method f, the top-level definitions in package <empty>, package <empty>, package <root>; enclosures = method f, the top-level definitions in package <empty>, package <empty>, package <root>
	at dotty.tools.dotc.transform.LambdaLift$Lifter.searchIn$1(LambdaLift.scala:137)
	at dotty.tools.dotc.transform.LambdaLift$Lifter.proxy(LambdaLift.scala:150)
	at dotty.tools.dotc.transform.LambdaLift$Lifter.proxyRef(LambdaLift.scala:168)
	at dotty.tools.dotc.transform.LambdaLift.transformIdent(LambdaLift.scala:287)
	at dotty.tools.dotc.transform.MegaPhase.goIdent(MegaPhase.scala:617)
	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:236)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:448)
	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:240)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:448)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:291)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
	at dotty.tools.dotc.transform.MegaPhase.loop$3(MegaPhase.scala:482)
	at dotty.tools.dotc.transform.MegaPhase.transformTrees(MegaPhase.scala:482)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:292)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:333)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
	at dotty.tools.dotc.transform.MegaPhase.loop$2$$anonfun$1(MegaPhase.scala:470)
	at dotty.tools.dotc.transform.MegaPhase.loop$2(MegaPhase.scala:472)
	at dotty.tools.dotc.transform.MegaPhase.transformBlock(MegaPhase.scala:472)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:311)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:333)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
	at dotty.tools.dotc.transform.MegaPhase.loop$2$$anonfun$1(MegaPhase.scala:470)
	at dotty.tools.dotc.transform.MegaPhase.loop$2(MegaPhase.scala:472)
	at dotty.tools.dotc.transform.MegaPhase.transformBlock(MegaPhase.scala:472)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:311)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
	at dotty.tools.dotc.transform.MegaPhase.mapDefDef$1(MegaPhase.scala:261)
	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:264)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:448)
	at dotty.tools.dotc.transform.MegaPhase.loop$1(MegaPhase.scala:461)
	at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:461)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:372)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:268)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:448)
	at dotty.tools.dotc.transform.MegaPhase.loop$1(MegaPhase.scala:461)
	at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:461)
	at dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:392)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:395)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:450)
	at dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:477)
	at dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:489)
	at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:354)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:360)
	at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:315)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
	at dotty.tools.dotc.Run.runPhases$1(Run.scala:337)
	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:348)
	at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:357)
	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:71)
	at dotty.tools.dotc.Run.compileUnits(Run.scala:357)
	at dotty.tools.dotc.Run.compileSources(Run.scala:261)
	at dotty.tools.dotc.Run.compile(Run.scala:246)
	at dotty.tools.dotc.Driver.doCompile(Driver.scala:37)
	at dotty.tools.dotc.Driver.process(Driver.scala:197)
	at dotty.tools.dotc.Driver.process(Driver.scala:165)
	at dotty.tools.dotc.Driver.process(Driver.scala:177)
	at dotty.tools.dotc.Driver.main(Driver.scala:207)
	at dotty.tools.dotc.Main.main(Main.scala)
Compilation failed

note: could be related to #19436

@nicolasstucki
Copy link
Contributor

Miminized
import compiletime.{summonInline, summonAll}

class DialectTypeMappers:
  given aString: String = ???

inline def metadata(dialect: DialectTypeMappers): Unit =
  import dialect.given
  summonInline[String]
  // summonAll[Tuple1[String]]

def f =
  metadata((??? : DialectTypeMappers))

scalac -Xprint:inlining shows

def f: Unit =
      {
        val dialect$proxy1: DialectTypeMappers = ??? :DialectTypeMappers
        {
          import dialect$proxy1.given
          {
            dialect.aString
            ()
          }
        }:Unit
      }

where dialect.aString should have been dialect$proxy1.aString

@nicolasstucki nicolasstucki added area:inline and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jan 22, 2024
@nicolasstucki
Copy link
Contributor

summon works correctly, therefore I assume that the context is properly updated with the correct import before expanding summonInline.

My best guess so far we are using the wrong context here https://github.com/lampepfl/dotty/blob/main/compiler/src/dotty/tools/dotc/inlines/Inlines.scala#L427-L437

@mbovel mbovel added the Spree Suitable for a future Spree label Feb 25, 2024
@mbovel
Copy link
Member

mbovel commented Feb 25, 2024

This issue was picked for the Issue Spree of Februrary 27th, 2024. @natsukagami, @KuceraMartin and @jan-pieter will be working on it. If you have any insight into the issue or guidance on how to fix it, please leave it here.

@natsukagami
Copy link
Contributor

Some more context:

Looking at InlinerMap, it seems that Import trees have their qualifiers renamed, but the underlying denotation is not changed. This is later used by Typer to infer the imported givens into the context (through importContext). That's how the dialect got through.

@mbovel
Copy link
Member

mbovel commented Apr 8, 2024

@EugeneFlesselle, do you plan to work on this?

@Gedochao Gedochao assigned EugeneFlesselle and unassigned jchyb Apr 8, 2024
@mbovel mbovel removed the Spree Suitable for a future Spree label May 20, 2024
@odersky odersky self-assigned this May 22, 2024
lihaoyi pushed a commit to com-lihaoyi/scalasql that referenced this issue May 25, 2024
Closes #2 

## Macros

Just like @KuceraMartin in #3, I ran into scala/scala3#19493 and
scala/scala3#19436 when trying to resolve a `TypeMapper` by importing
from a `DialectTypeMappers`. As a workaround, I introduced [additional
`implicit def`s in the `TableMapper` companion
object](https://github.com/com-lihaoyi/scalasql/blob/a7d6c531bf7b9cc2f5e2c175906d2a1e961de206/scalasql/core/src/TypeMapper.scala#L58-L121)
that instead rely on an implicit instance of `DialectTypeMappers`, i.e.
in a macro:

```scala
// bad, causes a compiler crash
// TableMacro.scala
(dialect: DialectTypeMappers) => {
  import dialect.*
  summonInline[TypeMapper[t]]
}

// good
// TypeMapper.scala
implicit def stringFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[String] = d.StringType

// TableMacro.scala
(dialect: DialectTypeMappers) => {
  given d: DialectTypeMappers = dialect
  summonInline[TypeMapper[t]]
}
```

## Supporting changes

In addition to building out the macros in Scala 3, the following changes
were necessary:

1. Update the generated code to ensure `def`s aren't too far to the left
-- this is to silence Scala 3 warnings
2. Convert `CharSequence`s to `String`s explicitly -- see the [error the
Scala 3 compiler reported
here](9ffeb06)
3. Remove `try` block without a corresponding `catch` -- see the
[warning the Scala 3 compiler reported
here](011c3f6)
4. Add types to implicit definitions
5. Mark `renderSql` as `private[scalasql]` instead of `protected` -- see
the [error the Scala 3 compiler reported
here](8e767e3)
6. Use Scala 3.4 -- this is a little unfortunate since it's not the LTS
but it's necessary for the Scala 3 macros to [match on higher kinded
types like
this](https://github.com/com-lihaoyi/scalasql/blob/a7d6c531bf7b9cc2f5e2c175906d2a1e961de206/scalasql/query/src-3/TableMacro.scala#L48-L52).
This type of match doesn't work in Scala 3.3
7. Replace `_` wildcards with `?` -- this is to silence Scala 3 warnings
8. Replace `Foo with Bar` in types with `Foo & Bar` -- this is to
silence Scala 3 warnings
9. Add the `-Xsource:3` compiler option for Scala 2 -- this is necessary
to use the language features mentioned in points 7 and 8
10. Add a number of type annotations to method overrides -- this is to
silence warnings reported by the Scala 2 compiler as a result of
enabling `-Xsource:3`. All of the warnings relate to the inferred type
of the method changing between Scala 2 and 3
EugeneFlesselle added a commit to dotty-staging/dotty that referenced this issue Jun 27, 2024
The inliner replaces references to parameters by
their corresponding proxys, including in singleton types.
It did not, however, handle the mapping over import types,
the symbols of which way have depended on parameters.

Mapping imports correctly was necessary for i19493
since the `summonInline` resolves post inlining to
a given imported within the inline definition.

Fix scala#19493
@odersky odersky closed this as completed in 413d7b4 Jul 2, 2024
odersky added a commit that referenced this issue Jul 2, 2024
The inliner replaces references to parameters by their corresponding
proxys, including in singleton types.
It did not handle the mapping over import types, the symbols of which
way have depended on parameters.

Both i19493 and i19436 require mapping the type of the expr in an
`ImportType` which is itself the info of a `TermRef`.
In the first issue, for the substitution of an inline def parameter
proxy.
In the second issue, for the parameter of a lambda returned from an
inline def.

Both can be handled in `TypeMap` by mapping over references to
`ImportType`s.
The second case also requires modifying `TreeTypeMap#mapType` such that
the logic mapping over imports is done within a `TypeMap` doing the
symbol substitutions.

Also note these mappings are only necessary for `summonInline`s (which
could have just been made non-inline) resolving
post-inlining to givens imported within the inline definition.

Fix #19493
Fix #19436
WojciechMazur pushed a commit to WojciechMazur/dotty that referenced this issue Jul 2, 2024
The inliner replaces references to parameters by
their corresponding proxys, including in singleton types.
It did not, however, handle the mapping over import types,
the symbols of which way have depended on parameters.

Mapping imports correctly was necessary for i19493
since the `summonInline` resolves post inlining to
a given imported within the inline definition.

Fix scala#19493
@Kordyjan Kordyjan added this to the 3.5.1 milestone Jul 3, 2024
WojciechMazur pushed a commit that referenced this issue Jul 10, 2024
The inliner replaces references to parameters by
their corresponding proxys, including in singleton types.
It did not, however, handle the mapping over import types,
the symbols of which way have depended on parameters.

Mapping imports correctly was necessary for i19493
since the `summonInline` resolves post inlining to
a given imported within the inline definition.

Fix #19493

[Cherry-picked 413d7b4]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants