Skip to content
Open
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
29 changes: 13 additions & 16 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1982,27 +1982,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

fn check_expr_tuple(
&self,
elts: &'tcx [hir::Expr<'tcx>],
elements: &'tcx [hir::Expr<'tcx>],
expected: Expectation<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let flds = expected.only_has_type(self).and_then(|ty| {
let ty = self.try_structurally_resolve_type(expr.span, ty);
match ty.kind() {
ty::Tuple(flds) => Some(&flds[..]),
_ => None,
}
let mut expectations = expected
.only_has_type(self)
.and_then(|ty| self.try_structurally_resolve_type(expr.span, ty).tuple())
.unwrap_or_default()
.iter();

let elements = elements.iter().map(|e| {
let ty = expectations.next().unwrap_or_else(|| self.next_ty_var(e.span));
self.check_expr_coercible_to_type(e, ty, None);
ty
});

let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds {
Some(fs) if i < fs.len() => {
let ety = fs[i];
self.check_expr_coercible_to_type(e, ety, None);
ety
}
_ => self.check_expr_with_expectation(e, NoExpectation),
});
let tuple = Ty::new_tup_from_iter(self.tcx, elt_ts_iter);
let tuple = Ty::new_tup_from_iter(self.tcx, elements);

if let Err(guar) = tuple.error_reported() {
Ty::new_error(self.tcx, guar)
} else {
Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1591,7 +1591,8 @@ impl<'tcx> Ty<'tcx> {
}
}

/// Iterates over tuple fields.
/// Returns a list of tuple fields.
///
/// Panics when called on anything but a tuple.
#[inline]
pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> {
Expand All @@ -1601,6 +1602,15 @@ impl<'tcx> Ty<'tcx> {
}
}

/// Returns a list of tuple type arguments, or `None` if `self` isn't a tuple.
#[inline]
pub fn tuple(self) -> Option<&'tcx List<Ty<'tcx>>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn tuple(self) -> Option<&'tcx List<Ty<'tcx>>> {
pub fn opt_tuple_fields(self) -> Option<&'tcx List<Ty<'tcx>>> {

seems like it does the same thing as tuple_fields it just doesnt panic

Copy link
Member Author

@WaffleLapkin WaffleLapkin Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is indeed the case, is there a problem with that? In the code I wrote I found this a lot more convenient than checking the type first.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no it's fine I just found the differences in the names doesn't really reflect the differences in behaviour

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have a better idea for the names I can rename them

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i suggested a different name already :P

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦🏻

I swear I sleep at night sometimes

match self.kind() {
Tuple(args) => Some(args),
_ => None,
}
}

/// If the type contains variants, returns the valid range of variant indices.
//
// FIXME: This requires the optimized MIR in the case of coroutines.
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/loops/loop-break-value.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,10 @@ LL | break (break, break);
| || |
| || expected because of this `break`
| |expected because of this `break`
| expected `()`, found `(!, !)`
| expected `()`, found `(_, _)`
|
= note: expected unit type `()`
found tuple `(!, !)`
found tuple `(_, _)`

error[E0308]: mismatched types
--> $DIR/loop-break-value.rs:89:15
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/never_type/diverging-tuple-parts-39485.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ error[E0308]: mismatched types
LL | fn f() -> isize {
| ----- expected `isize` because of return type
LL | (return 1, return 2)
| ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `(!, !)`
| ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `(_, _)`
|
= note: expected type `isize`
found tuple `(!, !)`
found tuple `(_, _)`

error: aborting due to 2 previous errors

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/never_type/issue-10176.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ fn f() -> isize { //~ NOTE expected `isize` because of return type
(return 1, return 2)
//~^ ERROR mismatched types
//~| NOTE expected type `isize`
//~| NOTE found tuple `(!, !)`
//~| NOTE expected `isize`, found `(!, !)`
//~| NOTE found tuple `(_, _)`
//~| NOTE expected `isize`, found `(_, _)`
}

fn main() {}
4 changes: 2 additions & 2 deletions tests/ui/never_type/issue-10176.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ error[E0308]: mismatched types
LL | fn f() -> isize {
| ----- expected `isize` because of return type
LL | (return 1, return 2)
| ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `(!, !)`
| ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `(_, _)`
|
= note: expected type `isize`
found tuple `(!, !)`
found tuple `(_, _)`

error: aborting due to 1 previous error

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/tuple/array-diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
fn main() {
let _tmp = [
("C200B40A82", 3),
("C200B40A83", 4) //~ ERROR: expected function, found `(&'static str, {integer})` [E0618]
("C200B40A83", 4) //~ ERROR: expected function, found `(&str, {integer})` [E0618]
("C200B40A8537", 5),
];
}
2 changes: 1 addition & 1 deletion tests/ui/tuple/array-diagnostics.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0618]: expected function, found `(&'static str, {integer})`
error[E0618]: expected function, found `(&str, {integer})`
--> $DIR/array-diagnostics.rs:4:9
|
LL | ("C200B40A83", 4)
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/tuple/coercion-never.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// This test checks if tuple elements are a coercion site or not.
// Note that the code here is a degenerate case, but you can get similar effects in real code, when
// unifying match arms, for example.
//
// See also coercion-slice.rs
//
//@ check-pass

fn main() {
let _: ((),) = (loop {},);

((),) = (loop {},);

let x = (loop {},);
let _: ((),) = x;
}
12 changes: 12 additions & 0 deletions tests/ui/tuple/coercion-slice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// This test checks if tuple elements are a coercion site or not.
// Note that the code here is a degenerate case, but you can get similar effects in real code, when
// unifying match arms, for example.
//
// See also: coercion-never.rs

fn main() {
let _: (&[u8],) = (&[],);

let y = (&[],);
let _: (&[u8],) = y; //~ error: mismatched types
}
14 changes: 14 additions & 0 deletions tests/ui/tuple/coercion-slice.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0308]: mismatched types
--> $DIR/coercion-slice.rs:11:23
|
LL | let _: (&[u8],) = y;
| -------- ^ expected `(&[u8],)`, found `(&[_; 0],)`
| |
| expected due to this
|
= note: expected tuple `(&[u8],)`
found tuple `(&[_; 0],)`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
Loading