Skip to content

Commit

Permalink
Fix widening logic to keep instantiation within bounds (#16417)
Browse files Browse the repository at this point in the history
Before this commit, if `Config.checkConstraintsSatisfiable` was set to
`true`, then tests/pos/cls.scala would fail on `val b1` with:

Y is constrained to be >: Matchable but attempted to instantiate it to
Int | String

This happens because when `widenInferred` widens a union, it constrains
the upper-bound of the parameter being instantiated to be a subtype of
that union (`tpw <:< bound`). This is usually fine, but if
`isTransparent` is true, we'll return the original unwidened type, which
is now out of bounds.

To avoid this inconsistency, the `isTransparent` check is now moved
before the subtype check that updates the bounds.
  • Loading branch information
odersky authored Nov 28, 2022
2 parents beb17fd + 9e11e8b commit 1b3a52c
Showing 1 changed file with 5 additions and 8 deletions.
13 changes: 5 additions & 8 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -624,8 +624,9 @@ trait ConstraintHandling {

/** Widen inferred type `inst` with upper `bound`, according to the following rules:
* 1. If `inst` is a singleton type, or a union containing some singleton types,
* widen (all) the singleton type(s), provided the result is a subtype of `bound`.
* (i.e. `inst.widenSingletons <:< bound` succeeds with satisfiable constraint)
* widen (all) the singleton type(s), provided the result is a subtype of `bound`
* (i.e. `inst.widenSingletons <:< bound` succeeds with satisfiable constraint) and
* is not transparent according to `isTransparent`.
* 2a. If `inst` is a union type and `widenUnions` is true, approximate the union type
* from above by an intersection of all common base types, provided the result
* is a subtype of `bound`.
Expand All @@ -647,7 +648,7 @@ trait ConstraintHandling {
def widenOr(tp: Type) =
if widenUnions then
val tpw = tp.widenUnion
if (tpw ne tp) && (tpw <:< bound) then tpw else tp
if (tpw ne tp) && !isTransparent(tpw, traitOnly = false) && (tpw <:< bound) then tpw else tp
else tp.hardenUnions

def widenSingle(tp: Type) =
Expand All @@ -663,11 +664,7 @@ trait ConstraintHandling {
else
val widenedFromSingle = widenSingle(inst)
val widenedFromUnion = widenOr(widenedFromSingle)
val widened =
if (widenedFromUnion ne widenedFromSingle) && isTransparent(widenedFromUnion, traitOnly = false) then
widenedFromSingle
else
dropTransparentTraits(widenedFromUnion, bound)
val widened = dropTransparentTraits(widenedFromUnion, bound)
widenIrreducible(widened)

wideInst match
Expand Down

0 comments on commit 1b3a52c

Please sign in to comment.