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

Module imports with different capitalization create phantom type conflicts #774

Open
jiribenes opened this issue Jan 13, 2025 · 3 comments
Labels
bug Something isn't working

Comments

@jiribenes
Copy link
Contributor

This is a fun bug that seems pretty hard to describe, but basically, there are two different "code paths" that reach a "different" Person even though it's actually the same exact file and type (which is a fact that Effekt doesn't understand).

Take a look at the minimal reproduction:

common.effekt

module common

record Person(name: String, birthYear: Int)

personutils.effekt

module personutils

import Common
// !!! notice the capitalisation here:
//  if you make it lowercase, everything works again

def calculateAge(p: Person, currentYear: Int) =
  p.birthYear - currentYear

main.effekt

module main

import common
import personutils

def main() = {
  val jolene = Person("Jolene", 1953)
  val age = calculateAge(jolene, 2025)
  // ^ ERROR: Expected Person but got Person
  println(age)
}
@jiribenes jiribenes added the bug Something isn't working label Jan 13, 2025
@jiribenes
Copy link
Contributor Author

Notes:

  • if you import a module of the exact same name multiple times, everything is OK
  • if you import both common and Common, the code now returns:
Ambiguous overload.
There are multiple overloads, which all would type check:
- common::Person: (String, Int) => Person
- common::Person: (String, Int) => Person

@jiribenes
Copy link
Contributor Author

jiribenes commented Jan 14, 2025

One minute debugging:

Tracing findSource leads to:

findSource: Trying to find: common
... ~> Some(FileSource(./common.effekt,UTF-8))
findSource: Trying to find: personutils
... ~> Some(FileSource(./personutils.effekt,UTF-8))
findSource: Trying to find: Common
... ~> Some(FileSource(./Common.effekt,UTF-8))

Now if you try getting the content of the Common file source, you get the same contents as the ./common.effekt file has.
The Source type and its .content comes from Kiama, and .content just uses scala.io.Source.fromFile, so that's where the investigation would lead next.
https://github.com/effekt-lang/kiama/blob/ca71c77bf9b04d1f6721660322631cfad7a2def5/shared/src/main/scala/kiama/util/Source.scala#L112

@jiribenes
Copy link
Contributor Author

jiribenes commented Jan 15, 2025

Had one more idea and one more minute. If you:

  1. remove the module common from common.effekt
  2. in main.effekt import both common and Common

then the error is:

There are multiple overloads, which all would type check:

  • common::Person: (String, Int) => Person
  • Common::Person: (String, Int) => Person

But if you revert step 1 (keep module common in common), the error is:

There are multiple overloads, which all would type check:

  • common::Person: (String, Int) => Person
  • common::Person: (String, Int) => Person

This seems to suggest that the module xyz declaration is at least partially taken into account for this...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant