Skip to content

Commit cd61e54

Browse files
committed
Bubble opaque types into aggregates to produce more precise diagnostics on aggregate constructors
1 parent 44e2a05 commit cd61e54

File tree

5 files changed

+68
-34
lines changed

5 files changed

+68
-34
lines changed

compiler/rustc_mir_build/src/build/expr/as_temp.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
66
use rustc_middle::middle::region;
77
use rustc_middle::mir::*;
88
use rustc_middle::thir::*;
9+
use rustc_middle::ty::Ty;
910

1011
impl<'a, 'tcx> Builder<'a, 'tcx> {
1112
/// Compile `expr` into a fresh temporary. This is used when building
@@ -21,7 +22,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2122
// this is the only place in mir building that we need to truly need to worry about
2223
// infinite recursion. Everything else does recurse, too, but it always gets broken up
2324
// at some point by inserting an intermediate temporary
24-
ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
25+
ensure_sufficient_stack(|| {
26+
self.as_temp_inner(block, temp_lifetime, expr, mutability, expr.ty)
27+
})
2528
}
2629

2730
fn as_temp_inner(
@@ -30,18 +33,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3033
temp_lifetime: Option<region::Scope>,
3134
expr: &Expr<'tcx>,
3235
mutability: Mutability,
36+
expr_ty: Ty<'tcx>,
3337
) -> BlockAnd<Local> {
3438
let this = self;
3539

3640
let expr_span = expr.span;
3741
let source_info = this.source_info(expr_span);
3842
if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
3943
return this.in_scope((region_scope, source_info), lint_level, |this| {
40-
this.as_temp(block, temp_lifetime, &this.thir[value], mutability)
44+
this.as_temp_inner(block, temp_lifetime, &this.thir[value], mutability, expr.ty)
4145
});
4246
}
4347

44-
let expr_ty = expr.ty;
4548
let temp = {
4649
let mut local_decl = LocalDecl::new(expr_ty, expr_span);
4750
if mutability == Mutability::Not {

compiler/rustc_mir_build/src/thir/cx/expr.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::build::ExprCategory as Category;
12
use crate::thir::cx::Cx;
23
use crate::thir::util::UserAnnotatedTyHelpers;
34
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -24,20 +25,26 @@ use rustc_target::abi::VariantIdx;
2425
impl<'tcx> Cx<'tcx> {
2526
crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
2627
// `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow.
27-
ensure_sufficient_stack(|| self.mirror_expr_inner(expr))
28+
ensure_sufficient_stack(|| self.mirror_expr_inner(expr, None))
2829
}
2930

30-
crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> {
31-
exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()
31+
crate fn mirror_exprs(
32+
&mut self,
33+
exprs: impl Iterator<Item = (&'tcx hir::Expr<'tcx>, Option<Ty<'tcx>>)>,
34+
) -> Box<[ExprId]> {
35+
exprs.map(|(expr, ty)| self.mirror_expr_inner(expr, ty)).collect()
3236
}
3337

34-
pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
38+
#[instrument(level = "debug", skip(self))]
39+
pub(super) fn mirror_expr_inner(
40+
&mut self,
41+
hir_expr: &'tcx hir::Expr<'tcx>,
42+
ty: Option<Ty<'tcx>>,
43+
) -> ExprId {
3544
let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id);
3645
let expr_scope =
3746
region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
3847

39-
debug!("Expr::make_mirror(): id={}, span={:?}", hir_expr.hir_id, hir_expr.span);
40-
4148
let mut expr = self.make_mirror_unadjusted(hir_expr);
4249

4350
let adjustment_span = match self.adjustment_span {
@@ -47,12 +54,16 @@ impl<'tcx> Cx<'tcx> {
4754

4855
// Now apply adjustments, if any.
4956
for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
50-
debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment);
57+
debug!(?expr, ?adjustment);
5158
let span = expr.span;
5259
expr =
5360
self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
5461
}
5562

63+
if !matches!(Category::of(&expr.kind), Some(Category::Constant)) {
64+
expr.ty = ty.unwrap_or(expr.ty);
65+
}
66+
5667
// Next, wrap this up in the expr's scope.
5768
expr = Expr {
5869
temp_lifetime,
@@ -172,7 +183,7 @@ impl<'tcx> Cx<'tcx> {
172183
// is guaranteed to exist, since a method call always has a receiver.
173184
let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span));
174185
tracing::info!("Using method span: {:?}", expr.span);
175-
let args = self.mirror_exprs(args);
186+
let args = self.mirror_exprs(args.iter().zip(std::iter::repeat(None)));
176187
self.adjustment_span = old_adjustment_span;
177188
ExprKind::Call {
178189
ty: expr.ty,
@@ -194,12 +205,16 @@ impl<'tcx> Cx<'tcx> {
194205

195206
let method = self.method_callee(expr, fun.span, None);
196207

197-
let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e));
208+
let arg_tys: Vec<_> =
209+
args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)).collect();
198210
let tupled_args = Expr {
199-
ty: self.tcx.mk_tup(arg_tys),
211+
ty: self.tcx.mk_tup(arg_tys.iter()),
200212
temp_lifetime,
201213
span: expr.span,
202-
kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
214+
kind: ExprKind::Tuple {
215+
fields: self
216+
.mirror_exprs(args.iter().zip(arg_tys.into_iter().map(Some))),
217+
},
203218
};
204219
let tupled_args = self.thir.exprs.push(tupled_args);
205220

@@ -256,7 +271,7 @@ impl<'tcx> Cx<'tcx> {
256271
ExprKind::Call {
257272
ty: self.typeck_results().node_type(fun.hir_id),
258273
fun: self.mirror_expr(fun),
259-
args: self.mirror_exprs(args),
274+
args: self.mirror_exprs(args.iter().zip(std::iter::repeat(None))),
260275
from_hir_call: true,
261276
fn_span: expr.span,
262277
}
@@ -763,10 +778,17 @@ impl<'tcx> Cx<'tcx> {
763778
ExprKind::Use { source: self.mirror_expr(source) }
764779
}
765780
hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) },
766-
hir::ExprKind::Array(ref fields) => {
767-
ExprKind::Array { fields: self.mirror_exprs(fields) }
768-
}
769-
hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
781+
hir::ExprKind::Array(ref fields) => ExprKind::Array {
782+
fields: self.mirror_exprs(
783+
fields
784+
.iter()
785+
.zip(std::iter::repeat(Some(expr_ty.sequence_element_type(self.tcx)))),
786+
),
787+
},
788+
hir::ExprKind::Tup(ref fields) => ExprKind::Tuple {
789+
fields: self
790+
.mirror_exprs(fields.iter().zip(expr_ty.tuple_fields().iter().map(Some))),
791+
},
770792

771793
hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr(v) },
772794
hir::ExprKind::Err => unreachable!(),
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/issue-86465.rs:6:5
2+
--> $DIR/issue-86465.rs:6:9
33
|
44
LL | (a, a)
5-
| ^^^^^^
6-
| |
7-
| expected `&'a u32`, got `&'b u32`
8-
| this expression supplies two conflicting concrete types for the same opaque type
5+
| ^ expected `&'a u32`, got `&'b u32`
6+
|
7+
note: previous use here
8+
--> $DIR/issue-86465.rs:6:6
9+
|
10+
LL | (a, a)
11+
| ^
912

1013
error: aborting due to previous error
1114

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
2+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:9
33
|
44
LL | (i, i)
5-
| ^^^^^^
6-
| |
7-
| expected `&'a i32`, got `&'b i32`
8-
| this expression supplies two conflicting concrete types for the same opaque type
5+
| ^ expected `&'a i32`, got `&'b i32`
6+
|
7+
note: previous use here
8+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:6
9+
|
10+
LL | (i, i)
11+
| ^
912

1013
error: aborting due to previous error
1114

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/multiple-def-uses-in-one-fn2.rs:10:5
2+
--> $DIR/multiple-def-uses-in-one-fn2.rs:10:17
33
|
44
LL | (a.clone(), a)
5-
| ^^^^^^^^^^^^^^
6-
| |
7-
| expected `A`, got `B`
8-
| this expression supplies two conflicting concrete types for the same opaque type
5+
| ^ expected `A`, got `B`
6+
|
7+
note: previous use here
8+
--> $DIR/multiple-def-uses-in-one-fn2.rs:10:6
9+
|
10+
LL | (a.clone(), a)
11+
| ^^^^^^^^^
912

1013
error: aborting due to previous error
1114

0 commit comments

Comments
 (0)