Skip to content

WIP #4721 try improving errors #4970

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,19 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
else {
assert(contains(param1))
assert(contains(param2))
// We add edge param1 <: param2 to the graph representing which params are known to be smaller
// than which other params, which is recorded in both lowerMap and upperMap.
// Since we store the *transitive closure* of the parameter subtyping relation, here
// we find all param0 <: param1, and param3 >: param2, and add all edges of form param0 <: param3,
// but without readding existing edges!

// Params param3 that *become* known-to-be-bigger than param1.
val newUpper = param2 :: exclusiveUpper(param2, param1)
// Params param0 that *become* known-to-be-bigger than param2.
val newLower = param1 :: exclusiveLower(param1, param2)
val current1 = (current /: newLower)(upperLens.map(this, _, _, newUpper ::: _))
val current2 = (current1 /: newUpper)(lowerLens.map(this, _, _, newLower ::: _))
// For each param0, prepend all param3 to the upper params.
val current1 = newLower.foldLeft(current)((curr, p) => upperLens.map(this, curr, p, upper => newUpper ::: upper))
val current2 = newUpper.foldLeft(current1)((curr, p) => lowerLens.map(this, curr, p, lower => newLower ::: lower))
current2
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1478,10 +1478,10 @@ object messages {
val explanation = ""
}

case class DoesNotConformToBound(tpe: Type, which: String, bound: Type)(
case class DoesNotConformToBound(tpe: Type, which: String, bound: Type, inferred: Boolean)(
err: typer.ErrorReporting.Errors)(implicit ctx: Context)
extends Message(DoesNotConformToBoundID) {
val msg = hl"Type argument ${tpe} does not conform to $which bound $bound ${err.whyNoMatchStr(tpe, bound)}"
val msg = hl"${if (inferred) "Inferred type" else "Type"} argument $tpe does not conform to $which bound $bound ${err.whyNoMatchStr(tpe, bound)}"
val kind = "Type Mismatch"
val explanation = ""
}
Expand Down
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ object Checking {
ctx.error(ex"missing type parameter(s) for $arg", arg.pos)
}
}
for ((arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate))
for ((arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate)) {
println(s"arg.pos ${arg.pos}, ${arg.pos.isSynthetic}")
ctx.error(
DoesNotConformToBound(arg.tpe, which, bound)(err),
arg.pos.focus)
DoesNotConformToBound(arg.tpe, which, bound, arg.pos.isZeroExtent)(err),
arg.pos.focus)
}
}

/** Check that type arguments `args` conform to corresponding bounds in `tl`
Expand Down
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,12 @@ object ProtoTypes {
else tl
val added = ensureFresh(tl)
val tvars = if (addTypeVars) newTypeVars(added) else Nil
ctx.typeComparer.addToConstraint(added, tvars.tpes.asInstanceOf[List[TypeVar]])
// addToConstraint can return false if the constraints have no solution, but it seems easier to detect and report
// any resulting bound violations later in PostTyper (see #4946). We still give a warning because the subsequent
// errors might be misleading.
if (!ctx.typeComparer.addToConstraint(added, tvars.tpes.asInstanceOf[List[TypeVar]]))
ctx.warning(s"Unsatisfiable type parameter constraints in polymorphic application", owningTree.pos)

(added, tvars)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -629,10 +629,11 @@ class ErrorMessagesTests extends ErrorMessagesTest {
.expect { (ictx, messages) =>
implicit val ctx: Context = ictx
assertMessageCount(1, messages)
val DoesNotConformToBound(tpe, which, bound) :: Nil = messages
val DoesNotConformToBound(tpe, which, bound, inferred) :: Nil = messages
assertEquals("Int", tpe.show)
assertEquals("upper", which)
assertEquals("List[Int]", bound.show)
assertEquals(true, inferred)
}

@Test def doesNotConformToSelfType =
Expand Down