scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.87k stars 1.06k forks source link

Opaque types are not definable at top level of REPL #9879

Closed mpilquist closed 1 week ago

mpilquist commented 4 years ago

Minimized code

➜  dotr -version
Starting dotty REPL...
Dotty compiler version 0.27.0-RC1 -- Copyright 2002-2020, LAMP/EPFL
scala> opaque type T = Int
1 |opaque type T = Int
  |^^^^^^
  |Illegal start of statement: no modifiers allowed here

scala> object Foo { opaque type T = Int }
// defined object Foo
abgruszecki commented 4 years ago

@mpilquist what semantics would you expect from top-level opaque types in the REPL?

som-snytt commented 4 years ago

I would expect scoped to the line:

scala> opaque type T = String ; def f: T = "hi"

similar to

scala> def f(s: String): Int = s.toInt ; def f(i: Int): Int = i+1   // ok, not local statements

I may not know whether or how a given line is wrapped.

mpilquist commented 4 years ago

I wanted to enter both an opaque type and a companion, which is currently prohibited, even if wrapping with an outer { /* put type and companion here */ }

abgruszecki commented 4 years ago

Yeah, I guess that makes sense. One may also want to copy top-level code from a file into a REPL, and we can define top-level opaque types in files.

In principle I think this should work, in practice it may boil down to how REPL encodes lines. I think right now every input corresponds to a class' body, which would imply we'd somehow need to add extra support for opaque types in class bodies.

tgodzik commented 3 years ago

How does REPL encode opaque type T = Int ?

Just wrap it in class REPL{ } or something like that? That seems to be fine for opaque types.

bishabosha commented 3 years ago

How does REPL encode opaque type T = Int ?

Just wrap it in class REPL{ } or something like that? That seems to be fine for opaque types.

it should be fine I think

scala> /*opaque*/ type T = Int
     | object T:
     |   def apply(i: Int): T = i
     | 
result of rs$line$1 after typer:
package repl$ {
  final lazy module val rs$line$1: repl$.rs$line$1$ = new repl$.rs$line$1$()
  final module class rs$line$1$() extends Object() { 
    this: repl$.rs$line$1.type =>
    type T = Int
    final lazy module val T: T$ = new T$()
    final module class T$() extends Object() { this: T.type =>
      def apply(i: Int): T = i
    }
  }
}
dwijnand commented 3 years ago

Yeah, I guess that makes sense. One may also want to copy top-level code from a file into a REPL, and we can define top-level opaque types in files.

In principle I think this should work, in practice it may boil down to how REPL encodes lines. I think right now every input corresponds to a class' body, which would imply we'd somehow need to add extra support for opaque types in class bodies.

Btw, this works correctly in the Scala 2 REPL, and what I mean by that is when you paste a multi-line block of code it doesn't get processed as line-prompt-line-... but as a single snippet. So bringing forward that support would deal with that use case.

[edit: actually looks like the Scala 3 REPL already does support that.]

SethTisue commented 3 years ago

Note that in both Scala 2 and Scala 3, the REPL allows you (because JLine 3 allows you) to press option-Return to continue the current input. (Rendering Scala 2's :paste unneeded, unless you need :paste -raw.)

nrinaudo commented 3 years ago

Just to add my two cents, I have an admittedly weird use case for the REPL supporting opaque types.

I maintain a tut-like tool: a tool that runs a REPL session, passes Scala blocks it finds in a markdown file, and pastes the result in an output markdown file. I use this to generate slides, articles, ... and be fully confident that my code samples are valid.

The REPL not supporting opaque types means I can't use my tools to use or explain opaque types to Scala beginners.

This is a weird, very niche use case that nobody else might have. Just thought it might be interesting to share.

SethTisue commented 3 years ago

Perhaps mdoc (the standard "tut-like" tool these days, now that tut is deprecated) is affected as well?

nrinaudo commented 3 years ago

I don't think so - it's my understanding that mdoc doesn't run a REPL session, but generates classes and runs a normal compiler.

Gedochao commented 4 months ago

Still valid.

scala repl -S 3.nightly                            
# Welcome to Scala 3.6.0-RC1-bin-20240703-75a15c2-NIGHTLY-git-75a15c2 (17, Java OpenJDK 64-Bit Server VM).
# Type in expressions for evaluation. Or try :help.
#                                                                                                                  
# scala> opaque type T = Int
# -- [E103] Syntax Error: --------------------------------------------------------
# 1 |opaque type T = Int
#   |^^^^^^
#   |Illegal start of statement: this modifier is not allowed here
#   |
#   | longer explanation available when compiling with `-explain`
#                                                                                                                  
# scala> 

While of course:

scala compile --scala-snippet 'opaque type T = Int' -S 3.nightly
# Compiling project (Scala 3.6.0-RC1-bin-20240703-75a15c2-NIGHTLY, JVM (17))
# Compiled project (Scala 3.6.0-RC1-bin-20240703-75a15c2-NIGHTLY, JVM (17))