Skip to content

Add maybe types - #26814

Closed
odersky wants to merge 40 commits into
scala:mainfrom
dotty-staging:add-maybe-types
Closed

Add maybe types#26814
odersky wants to merge 40 commits into
scala:mainfrom
dotty-staging:add-maybe-types

Conversation

@odersky

@odersky odersky commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Trial balloon for a new kind of maybe type T?.

@odersky
odersky force-pushed the add-maybe-types branch 5 times, most recently from 339631c to d740b53 Compare August 21, 2026 14:44
@odersky
odersky force-pushed the add-maybe-types branch 2 times, most recently from 5744e79 to cd3d5d3 Compare August 23, 2026 20:33
val year = y.parseInt?
provided(1 <= day && day <= 31)
provided(1 <= month && month <= 12)
if 1 <= day && day <= 31

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

amazing

val month = m.parseInt.withErr(s"malformed month: $m")?
val year = y.parseInt.withErr(s"malformed year: $y")?
if 1 <= day && day <= 31 else s"day $day outside allowed range 1..31"
if 1 <= month && month <= 12 else s"month $month outside allowed range 1..12"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

incredible

case Invoice(customerId: String, amount: BigInt)
case Refund(invoiceId: String, reason: String)

def validateJson(json: JsonDict): Result[InvoiceOrRefund, List[String]] =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@odersky this is the example of the cumulative error scope

@odersky
odersky force-pushed the add-maybe-types branch 2 times, most recently from 7d57d29 to 2bdf8fe Compare August 24, 2026 14:30
inline def apply[T](x: T): Maybe[T, Nothing] = {
if x == null then new Valid(null)
else if x.isInstanceOf[Valid] then new Valid(x)
else x

@Ichoran Ichoran Aug 26, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This encoding declares (A ? E) ? F to be isomorphic to A ? (E | F) because Ok(Err(e)) falls through to the else x case. If this is what we intend, the type system should know about it. Otherwise, we need to either statically know that the actual T is disjoint from A ? E for all A, E; or we need a test for Valid or Fail, so that we encode Ok(Err(e)) as Valid(Fail(e)).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Indeed. It's fixed in the latest commit.

@odersky
odersky force-pushed the add-maybe-types branch 2 times, most recently from 2a34add to ed7cedc Compare August 27, 2026 16:48
odersky added 15 commits August 27, 2026 22:30
 - Enabled by experimental.magic
 - Independent of language.postfixOps
 - Highest precedence
ExtractDependencies fell into a "NoDenotation cannot be cast to ClassDenotation"
assertioin violation. When recompiling after some changes. This fix avoids that.
Otherwise the maybe logic does not work correctly.

It would be nice if we could link explicit-nulls with magic, but that does not
work since explicit-nulls is a global flag that has to be set when the compiler
starts up. We can't even change it from run to run.
Special cases needed for subtyping, erasure, and pattern matching.
The erasure of Maybe changes after bootstrapped. So anything that
touches it can compile only with the bootstrapped compiler.
Also: Drop $ in front of Maybe, no harm in using it directly, since it is a sealed
trait.

Also: Fix exhaustivity checking for Ok patterns
 - Drop OK unapply call, which is known to be the identity
 - Simplify leading null test for maybe types
Also, move back bootstrapped library and tests to regular. Since we now inline
Ok.unapply, we are no longer affected by difference in erasure between
bootstrapped and non-bootstrapped.
Plus a lot more tests
Needed to avoid erasure difference between bootstrapped and non-bootstrapped compilers.
odersky added 13 commits August 27, 2026 22:30
Also: drop overfitted condition by Claude in space engine.
To reduce added linecount we drop a bunch of tests that are straightforward Option -> ?
substitutions.
That ensures

  Ok(x) == Ok(x)
  Err(y) == Err(y)
The correct location is in run-bootstrapped
Comes with the following bug fixes:

 1. Maybe arguments should not be boxed.
 2. Capture sets of module vals need to be interpolated
 3. When reporting overriding errors under -explain, use isSubTypeWhenFrozen
 4. Interpolate self types of modules downwards
 5. Make Tuple a Pure trait (fails i13968-maybe.scala otherwise)
Flag an error only if two different source versions are implied.

Reason: We might have set the source to future and a language import
might also imply source future. That should be OK.
This used to also include nulls but that makes no sense: null.isInstanceOf
does not diverge, it just returns false. The ok-tostring test shows
that always false should not yield a warning, since this might
come from inlined code.
I have no idea what goes on here. MimaFilter error messages are not specific enough
to figure out whether they mean forwards or backwards compatibility.
@odersky
odersky force-pushed the add-maybe-types branch 2 times, most recently from 0ddea2f to be3fd7c Compare August 31, 2026 06:49
@odersky

odersky commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #26956.

@odersky odersky closed this Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants