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

Illegal MatchType Error reaches the backend #19434

Closed
odersky opened this issue Jan 12, 2024 · 7 comments · Fixed by #20017
Closed

Illegal MatchType Error reaches the backend #19434

odersky opened this issue Jan 12, 2024 · 7 comments · Fixed by #20017

Comments

@odersky
Copy link
Contributor

odersky commented Jan 12, 2024

Compiler version

3.4.0

Minimized example

object Test:

  object Named:
    opaque type Named[name <: String & Singleton, A] >: A = A

  type DropNames[T <: Tuple] = T match
    case Named.Named[_, x] *: xs => x *: DropNames[xs]
    case _ => T

  def f[T <: Tuple]: DropNames[T] = ???

Output

an unexpected type representation reached the compiler backend while compiling named-tuples-strawman.scala: dotty.tools.dotc.core.Types$PreviousErrorType@2d9dff65. If possible, please file a bug on https://github.com/lampepfl/dotty/issues
scala.MatchError: dotty.tools.dotc.core.Types$PreviousErrorType@2d9dff65 (of class dotty.tools.dotc.core.Types$PreviousErrorType)
	at dotty.tools.backend.jvm.BCodeHelpers.dotty$tools$backend$jvm$BCodeHelpers$$typeToTypeKind(BCodeHelpers.scala:764)
	at dotty.tools.backend.jvm.BCodeHelpers$BCInnerClassGen.toTypeKind(BCodeHelpers.scala:202)
	at dotty.tools.backend.jvm.BCodeHelpers$BCInnerClassGen.toTypeKind$(BCodeHelpers.scala:130)
	at dotty.tools.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.toTypeKind(BCodeSkelBuilder.scala:134)
	at dotty.tools.backend.jvm.BCodeHelpers$BCInnerClassGen.asmMethodType(BCodeHelpers.scala:188)
	at dotty.tools.backend.jvm.BCodeHelpers$BCInnerClassGen.asmMethodType$(BCodeHelpers.scala:130)
	at dotty.tools.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.asmMethodType(BCodeSkelBuilder.scala:134)
	at dotty.tools.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.genDefDef(BCodeSkelBuilder.scala:815)
	at dotty.tools.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.gen(BCodeSkelBuilder.scala:693)
	at dotty.tools.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.gen$$anonfun$1(BCodeSkelBuilder.scala:699)
	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.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.gen(BCodeSkelBuilder.scala:699)
	at dotty.tools.backend.jvm.BCodeSkelBuilder$PlainSkelBuilder.genPlainClass(BCodeSkelBuilder.scala:293)
	at dotty.tools.backend.jvm.CodeGen.genClass(CodeGen.scala:154)
	at dotty.tools.backend.jvm.CodeGen.genClassDef$1(CodeGen.scala:62)
	at dotty.tools.backend.jvm.CodeGen.genClassDefs$1(CodeGen.scala:117)
	at dotty.tools.backend.jvm.CodeGen.genClassDefs$1$$anonfun$1(CodeGen.scala:115)
	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.backend.jvm.CodeGen.genClassDefs$1(CodeGen.scala:115)
	at dotty.tools.backend.jvm.CodeGen.genUnit(CodeGen.scala:120)
	at dotty.tools.backend.jvm.GenBCode.run(GenBCode.scala:83)
	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.backend.jvm.GenBCode.runOn(GenBCode.scala:91)
	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:69)
	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)
Error while emitting named-tuples-strawman.scala
dotty.tools.dotc.core.Types$PreviousErrorType@2d9dff65 (of class dotty.tools.dotc.core.Types$PreviousErrorType)
1 warning found
1 error found

Expectation

A regular error, like this one:

1 |object Test:
  |       ^
  |       The match type contains an illegal case:
  |           case Test.Named.Named[_, x] *: xs => x *: Test.DropNames[xs]
  |       (this error can be ignored for now with `-source:3.3`)

I verified that that was the error that generated the illegal error type.

@odersky odersky added stat:needs triage Every issue needs to have an "area" and "itype" label itype:bug area:match-types and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jan 12, 2024
@odersky
Copy link
Contributor Author

odersky commented Jan 12, 2024

Also, I am not sure why this program would be illegal. I guess it should not be.

The problem seems to be that the match type is reduced only at erasure. At that time, opaque types are already eliminated, so Named looks like a normal type alias. So the type comparer complains.

@odersky
Copy link
Contributor Author

odersky commented Jan 12, 2024

Here's the stacktrace I see when I add a new Error().printStackTrace() to line 3573 of TypeComparer where the ErrorType gets generated:

	at dotty.tools.dotc.core.TrackingTypeComparer.recur$2(TypeComparer.scala:3574)
	at dotty.tools.dotc.core.TrackingTypeComparer.op$proxy82$1(TypeComparer.scala:3614)
	at dotty.tools.dotc.core.TrackingTypeComparer.matchCases(TypeComparer.scala:3615)
	at dotty.tools.dotc.core.Types$MatchType.matchCases$1(Types.scala:5041)
	at dotty.tools.dotc.core.Types$MatchType.reduced$$anonfun$1(Types.scala:5050)
	at dotty.tools.dotc.core.TypeComparer.inSubComparer(TypeComparer.scala:3054)
	at dotty.tools.dotc.core.TypeComparer.tracked(TypeComparer.scala:3064)
	at dotty.tools.dotc.core.TypeComparer$.tracked(TypeComparer.scala:3232)
	at dotty.tools.dotc.core.Types$MatchType.reduced(Types.scala:5050)
	at dotty.tools.dotc.core.Types$MatchType.tryNormalize(Types.scala:4999)
	at dotty.tools.dotc.core.Types$AppliedType.tryMatchAlias$1$$anonfun$1(Types.scala:4562)
	at dotty.tools.dotc.core.MatchTypeTrace$.recurseWith(MatchTypeTrace.scala:81)
	at dotty.tools.dotc.core.Types$AppliedType.tryMatchAlias$1(Types.scala:4563)
	at dotty.tools.dotc.core.Types$AppliedType.tryNormalize(Types.scala:4568)
	at dotty.tools.dotc.core.Types$AppliedType.translucentSuperType(Types.scala:4541)
	at dotty.tools.dotc.core.TypeErasure.checkedSuperType(TypeErasure.scala:752)
	at dotty.tools.dotc.core.TypeErasure.dotty$tools$dotc$core$TypeErasure$$apply(TypeErasure.scala:642)
	at dotty.tools.dotc.core.TypeErasure.eraseResult(TypeErasure.scala:879)
	at dotty.tools.dotc.core.TypeErasure.eraseInfo(TypeErasure.scala:815)
	at dotty.tools.dotc.core.TypeErasure$.transformInfo(TypeErasure.scala:273)
	at dotty.tools.dotc.transform.Erasure.transform(Erasure.scala:96)
	at dotty.tools.dotc.core.Denotations$SingleDenotation.goForward$1(Denotations.scala:831)
	at dotty.tools.dotc.core.Denotations$SingleDenotation.current(Denotations.scala:877)
	at dotty.tools.dotc.core.Symbols$Symbol.recomputeDenot(Symbols.scala:124)
	at dotty.tools.dotc.core.Symbols$Symbol.computeDenot(Symbols.scala:118)
	at dotty.tools.dotc.core.Symbols$Symbol.denot(Symbols.scala:111)
	at dotty.tools.dotc.core.Symbols$.toDenot(Symbols.scala:520)
	at dotty.tools.dotc.core.SymDenotations$ClassDenotation.paramAccessors$$anonfun$1(SymDenotations.scala:2386)
	at dotty.tools.dotc.core.Scopes$Scope.filter(Scopes.scala:103)
	at dotty.tools.dotc.core.SymDenotations$ClassDenotation.paramAccessors(SymDenotations.scala:2386)
	at dotty.tools.dotc.core.Contexts$Context.superCallContext(Contexts.scala:417)
	at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:2720)
	at dotty.tools.dotc.transform.Erasure$Typer.typedClassDef(Erasure.scala:1047)

@sjrd
Copy link
Member

sjrd commented Jan 23, 2024

Definitely a problem in erasure. During erasure, when trying to reduce the match type before erasing its bound, I observe a weird behavior. It sees as tycon of the match case pattern Test.Named.Named -- so far so good. But tycon.info gives [name <: String & Singleton,A] = A. That does not seem correct to me. At erasure, the info should still be the public abstract bounds >: [name] =>> Tupe <: [name] =>> Any. Shouldn't it? ctx.phase is erasure when it computes that.

@odersky
Copy link
Contributor Author

odersky commented Jan 23, 2024

No, opaque type aliases are eliminated before erasure, at phase ElimOpaque.

@sjrd
Copy link
Member

sjrd commented Jan 23, 2024

Oh. Well at least that explains it. It will make this tricky to fix, though. I'll have to think about it more.

@odersky
Copy link
Contributor Author

odersky commented Feb 1, 2024

I just hit this in the wild with some test code using NamedTuples.

@dwijnand
Copy link
Member

dwijnand commented Feb 1, 2024

I'm merging ElimOpaque into Erasure

EugeneFlesselle added a commit to EugeneFlesselle/dotty that referenced this issue Mar 25, 2024
This is another case which used to result in an unreported `ErrorType`
It is now detected only when enabling `-Yforce-sbt-phases -Xverify-signatures -Ycheck:all`

The error comes from:
```scala
type Names[X <: AnyNamedTuple] <: Tuple = X match
  case NamedTuple[n, _] => n
```
The `NamedTuple` pattern is legal as long as the type alias is opaque.
Following elimOpaque however, it is beta-reduced (as normal applied type aliases in match type patterns)
to a pattern which no longer contains an instance of the type capture `n`, making it an illegal pattern.
This used to return an `ErrorType`, which happened not be reported as in the other cases.

Also note this error could also be missed without the New footprint calculation scheme (scala#19639)

Given the changes to the footprint calculation and failed reduction reporting,
this is now the same issue as scala#19434.
@Kordyjan Kordyjan added this to the 3.5.0 milestone May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment