Skip to content

Commit b9f9347

Browse files
authored
Merge pull request #10672 from dotty-staging/fix-5077
Fix #5077: avoid pattern-bound type for selectors
2 parents 9000958 + 07f9303 commit b9f9347

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,15 @@ object PatternMatcher {
9494
*/
9595
private val initializer = MutableSymbolMap[Tree]()
9696

97-
private def newVar(rhs: Tree, flags: FlagSet): TermSymbol =
97+
private def newVar(rhs: Tree, flags: FlagSet, tpe: Type): TermSymbol =
9898
newSymbol(ctx.owner, PatMatStdBinderName.fresh(), Synthetic | Case | flags,
99-
sanitize(rhs.tpe), coord = rhs.span)
99+
sanitize(tpe), coord = rhs.span)
100100
// TODO: Drop Case once we use everywhere else `isPatmatGenerated`.
101101

102102
/** The plan `let x = rhs in body(x)` where `x` is a fresh variable */
103-
private def letAbstract(rhs: Tree)(body: Symbol => Plan): Plan = {
104-
val vble = newVar(rhs, EmptyFlags)
103+
private def letAbstract(rhs: Tree, tpe: Type = NoType)(body: Symbol => Plan): Plan = {
104+
val declTpe = if tpe.exists then tpe else rhs.tpe
105+
val vble = newVar(rhs, EmptyFlags, declTpe)
105106
initializer(vble) = rhs
106107
LetPlan(vble, body(vble))
107108
}
@@ -223,6 +224,13 @@ object PatternMatcher {
223224
/** Plan for matching `scrutinee` symbol against `tree` pattern */
224225
private def patternPlan(scrutinee: Symbol, tree: Tree, onSuccess: Plan): Plan = {
225226

227+
extension (tree: Tree) def avoidPatBoundType(): Type =
228+
tree.tpe.widen match
229+
case tref: TypeRef if tref.symbol.isPatternBound =>
230+
defn.AnyType
231+
case _ =>
232+
tree.tpe
233+
226234
/** Plan for matching `selectors` against argument patterns `args` */
227235
def matchArgsPlan(selectors: List[Tree], args: List[Tree], onSuccess: Plan): Plan = {
228236
/* For a case with arguments that have some test on them such as
@@ -243,7 +251,7 @@ object PatternMatcher {
243251
*/
244252
def matchArgsSelectorsPlan(selectors: List[Tree], syms: List[Symbol]): Plan =
245253
selectors match {
246-
case selector :: selectors1 => letAbstract(selector)(sym => matchArgsSelectorsPlan(selectors1, sym :: syms))
254+
case selector :: selectors1 => letAbstract(selector, selector.avoidPatBoundType())(sym => matchArgsSelectorsPlan(selectors1, sym :: syms))
247255
case Nil => matchArgsPatternPlan(args, syms.reverse)
248256
}
249257
def matchArgsPatternPlan(args: List[Tree], syms: List[Symbol]): Plan =

tests/run/i5077.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
A String with length 4
2+
A String with length 4
3+
A String with length 4

tests/run/i5077.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
trait Is[A]
2+
case object IsInt extends Is[Int]
3+
case object IsString extends Is[String]
4+
case class C[A](is: Is[A], value: A)
5+
6+
@main
7+
def Test = {
8+
val c_string: C[String] = C(IsString, "name")
9+
val c_any: C[_] = c_string
10+
val any: Any = c_string
11+
12+
// Case 1: no error
13+
// `IsInt.equals` might be overridden to match a value of `C[String]`
14+
c_string match {
15+
case C(IsInt, _) => println(s"An Int") // Can't possibly happen!
16+
case C(IsString, s) => println(s"A String with length ${s.length}")
17+
case _ => println("No match")
18+
}
19+
20+
// Case 2: Should match the second case and print the length of the string
21+
c_any match {
22+
case C(IsInt, i) if i < 10 => println(s"An Int less than 10")
23+
case C(IsString, s) => println(s"A String with length ${s.length}")
24+
case _ => println("No match")
25+
}
26+
27+
// Case 3: Same as above; should match the second case and print the length of the string
28+
any match {
29+
case C(IsInt, i) if i < 10 => println(s"An Int less than 10")
30+
case C(IsString, s) => println(s"A String with length ${s.length}")
31+
case _ => println("No match")
32+
}
33+
}

0 commit comments

Comments
 (0)