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 @@ -1939,27 +1939,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 @@ -1560,7 +1560,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 @@ -1570,6 +1571,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>>> {
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
21 changes: 21 additions & 0 deletions tests/ui/tuple/coercion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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.

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

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

let x = (loop {},);
let _: ((),) = x;

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

// This one can't work without a redesign on the coercion system.
// We currently only eagerly add never-to-any coercions, not any others.
// Thus, because we don't have an expectation when typechecking `&[]`,
// we don't add a coercion => this doesn't work.
let y = (&[],);
let _: (&[u8],) = y; //~ error: mismatched types
}
14 changes: 14 additions & 0 deletions tests/ui/tuple/coercion.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0308]: mismatched types
--> $DIR/coercion.rs:20: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