diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 16516a61f99b..a03a2f5cf4c6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1718,7 +1718,19 @@ trait Applications extends Compatibility { def typedUnApply(tree: untpd.Apply, selType0: Type)(using Context): Tree = { record("typedUnApply") val Apply(qual, unadaptedArgs) = tree - val selType = selType0.stripNamedTuple + // If the selector type is a tuple, then try using the element types from the tree if it's itself a tuple, + // e.g., if `(a: Any, b: Any)` is matched with `x @ (_, y: Int)` then `x` should be of type `(Any, Int)` + val selType = selType0 match + case AppliedType(selCon, selArgs) if defn.isTupleClass(selCon.typeSymbol) && unadaptedArgs.length == selArgs.length => + val newSelArgs = unadaptedArgs.zip(selArgs).map: + case (Typed(_, tpt: AppliedTypeTree), t) => + // However, we can't do that if the args changed, e.g., if the args were patterns + typed(tpt) match + case tpt2: AppliedTypeTree if tpt.args == tpt2.args => tpt2.tpe + case _ => t + case (_, t) => t + AppliedType(selCon, newSelArgs) + case st => st.stripNamedTuple def notAnExtractor(tree: Tree): Tree = // prefer inner errors diff --git a/tests/pos/match-precise-type-unchecked.scala b/tests/pos/match-precise-type-unchecked.scala new file mode 100644 index 000000000000..64ebc09ed4ec --- /dev/null +++ b/tests/pos/match-precise-type-unchecked.scala @@ -0,0 +1,15 @@ +import scala.collection.* +import scala.util.* + +val (ss: Seq[Success[Int] @unchecked], fs: Seq[Failure[Int] @unchecked]) = + Seq.empty[Try[Int]].partition(_.isSuccess).runtimeChecked + +val (ss2: Seq[Success[Int]], fs2: Seq[Failure[Int]]) = Seq.empty[Try[Int]].partition(_.isSuccess).runtimeChecked match + case (s: Seq[Success[Int] @unchecked], f: Seq[Failure[Int] @unchecked]) => (s, f) + +val (ss3: Seq[Success[Int]], fs3: Seq[Failure[Int]]) = Seq.empty[Try[Int]].partition(_.isSuccess).runtimeChecked match + case x @ (s: Seq[Success[Int] @unchecked], f: Seq[Failure[Int] @unchecked]) => x + +val (ss4, fs4: Seq[Failure[Int]]) = Seq.empty[Try[Int]].partition(_.isSuccess).runtimeChecked match + case x @ (_, f: Seq[Failure[Int] @unchecked]) => x + diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 2c97be5ed2b7..c0a1124e50b0 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -5059,8 +5059,8 @@ _empty_/Txn# => trait Txn [typeparam T <: Txn[T]] extends Object { self: Txn[T] _empty_/Txn#[T] => typeparam T <: Txn[T] _empty_/Txn#``(). => primary ctor [typeparam T <: Txn[T]](): Txn[T] local0 => val local out: Repr[Out] -local1 => val local inObj: Obj[In] & Repr[In] -local2 => val local outObj: Obj[Out] & Repr[Out] +local1 => val local inObj: Obj[In] +local2 => val local outObj: Obj[Out] Occurrences: [1:6..1:9): Txn <- _empty_/Txn#