diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 9242c6aeb8b28..927eb080b2008 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -1,6 +1,7 @@ //! The entry point of the NLL borrow checker. use rustc_data_structures::vec_map::VecMap; +use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; @@ -8,7 +9,7 @@ use rustc_middle::mir::{ BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, }; -use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid}; +use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid}; use rustc_span::symbol::sym; use std::env; use std::fmt::Debug; @@ -43,7 +44,7 @@ pub type PoloniusOutput = Output; /// closure requirements to propagate, and any generated errors. crate struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: VecMap, OpaqueHiddenType<'tcx>>, + pub opaque_type_values: VecMap>, pub polonius_input: Option>, pub polonius_output: Option>, pub opt_closure_req: Option>, @@ -372,7 +373,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, - opaque_type_values: &VecMap, OpaqueHiddenType<'tcx>>, + opaque_type_values: &VecMap>, errors: &mut crate::error::BorrowckErrors<'tcx>, ) { let tcx = infcx.tcx; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 0bb6559e65452..fa07c4fa9491d 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; +use rustc_hir::def_id::DefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::subst::GenericArgKind; @@ -54,8 +55,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'tcx>, opaque_ty_decls: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, - ) -> VecMap, OpaqueHiddenType<'tcx>> { - let mut result: VecMap, OpaqueHiddenType<'tcx>> = VecMap::new(); + ) -> VecMap> { + let mut result: VecMap> = VecMap::new(); for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { let substs = opaque_type_key.substs; debug!(?concrete_type, ?substs); @@ -124,21 +125,24 @@ impl<'tcx> RegionInferenceContext<'tcx> { // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to `(X, Y)` // and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we only know that // once we convert the generic parameters to those of the opaque type. - if let Some(prev) = result.get_mut(&opaque_type_key) { + if let Some(prev) = result.get_mut(&opaque_type_key.def_id) { if prev.ty != ty { - let mut err = infcx.tcx.sess.struct_span_err( - concrete_type.span, - &format!("hidden type `{}` differed from previous `{}`", ty, prev.ty), - ); - err.span_note(prev.span, "previous hidden type bound here"); - err.emit(); + if !ty.references_error() { + prev.report_mismatch( + &OpaqueHiddenType { ty, span: concrete_type.span }, + infcx.tcx, + ); + } prev.ty = infcx.tcx.ty_error(); } // Pick a better span if there is one. // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. prev.span = prev.span.substitute_dummy(concrete_type.span); } else { - result.insert(opaque_type_key, OpaqueHiddenType { ty, span: concrete_type.span }); + result.insert( + opaque_type_key.def_id, + OpaqueHiddenType { ty, span: concrete_type.span }, + ); } } result diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index cee510a42413a..4d4eed179ca9d 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -9,7 +9,6 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::IndexVec; -use rustc_middle::ty::OpaqueTypeKey; use rustc_span::Span; use rustc_target::abi::VariantIdx; use smallvec::SmallVec; @@ -242,7 +241,7 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: VecMap, OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: VecMap>, pub closure_requirements: Option>, pub used_mut_upvars: SmallVec<[Field; 8]>, pub tainted_by_errors: Option, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 45a215354d081..6e3dc92a2332f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1112,6 +1112,26 @@ pub struct OpaqueHiddenType<'tcx> { pub ty: Ty<'tcx>, } +impl<'tcx> OpaqueHiddenType<'tcx> { + pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) { + // Found different concrete types for the opaque type. + let mut err = tcx.sess.struct_span_err( + other.span, + "concrete type differs from previous defining opaque type use", + ); + err.span_label(other.span, format!("expected `{}`, got `{}`", self.ty, other.ty)); + if self.span == other.span { + err.span_label( + self.span, + "this expression supplies two conflicting concrete types for the same opaque type", + ); + } else { + err.span_note(self.span, "previous use here"); + } + err.emit(); + } +} + rustc_index::newtype_index! { /// "Universes" are used during type- and trait-checking in the /// presence of `for<..>` binders to control what sets of names are diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index b627b0763a286..83330720dde40 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -94,6 +94,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// Like `as_local_call_operand`, except that the argument will /// not be valid once `scope` ends. + #[instrument(level = "debug", skip(self))] crate fn as_operand( &mut self, mut block: BasicBlock, @@ -101,7 +102,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, local_info: Option>>, ) -> BlockAnd> { - debug!("as_operand(block={:?}, expr={:?} local_info={:?})", block, expr, local_info); let this = self; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { @@ -113,7 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let category = Category::of(&expr.kind).unwrap(); - debug!("as_operand: category={:?} for={:?}", category, expr.kind); + debug!(?category, ?expr.kind); match category { Category::Constant => { let constant = this.as_constant(expr); @@ -129,13 +129,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] crate fn as_call_operand( &mut self, mut block: BasicBlock, scope: Option, expr: &Expr<'tcx>, ) -> BlockAnd> { - debug!("as_call_operand(block={:?}, expr={:?})", block, expr); let this = self; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 3b3120cf04b7f..1b6eebc243322 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -420,6 +420,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.expr_as_place(block, expr, Mutability::Not, None) } + #[instrument(level = "debug", skip(self))] fn expr_as_place( &mut self, mut block: BasicBlock, @@ -427,8 +428,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mutability: Mutability, fake_borrow_temps: Option<&mut Vec>, ) -> BlockAnd> { - debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability); - let this = self; let expr_span = expr.span; let source_info = this.source_info(expr_span); diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 3f8a1a3f79504..ee3737415d98d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -31,14 +31,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Compile `expr`, yielding an rvalue. + #[instrument(level = "debug", skip(self))] crate fn as_rvalue( &mut self, mut block: BasicBlock, scope: Option, expr: &Expr<'tcx>, ) -> BlockAnd> { - debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr); - let this = self; let expr_span = expr.span; let source_info = this.source_info(expr_span); diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 6067da2f69b48..82a2d49ef3009 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -6,10 +6,12 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::*; +use rustc_middle::ty::Ty; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building /// up rvalues so as to freeze the value that will be consumed. + #[instrument(level = "debug", skip(self))] crate fn as_temp( &mut self, block: BasicBlock, @@ -20,7 +22,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // this is the only place in mir building that we need to truly need to worry about // infinite recursion. Everything else does recurse, too, but it always gets broken up // at some point by inserting an intermediate temporary - ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability)) + ensure_sufficient_stack(|| { + self.as_temp_inner(block, temp_lifetime, expr, mutability, expr.ty) + }) } fn as_temp_inner( @@ -29,22 +33,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_lifetime: Option, expr: &Expr<'tcx>, mutability: Mutability, + expr_ty: Ty<'tcx>, ) -> BlockAnd { - debug!( - "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})", - block, temp_lifetime, expr, mutability - ); let this = self; let expr_span = expr.span; let source_info = this.source_info(expr_span); if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { return this.in_scope((region_scope, source_info), lint_level, |this| { - this.as_temp(block, temp_lifetime, &this.thir[value], mutability) + this.as_temp_inner(block, temp_lifetime, &this.thir[value], mutability, expr.ty) }); } - let expr_ty = expr.ty; let temp = { let mut local_decl = LocalDecl::new(expr_ty, expr_span); if mutability == Mutability::Not { diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a8f623dbe4693..cf89125157c0c 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -15,14 +15,13 @@ use std::iter; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. + #[instrument(level = "debug", skip(self))] crate fn expr_into_dest( &mut self, destination: Place<'tcx>, mut block: BasicBlock, expr: &Expr<'tcx>, ) -> BlockAnd<()> { - debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr); - // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to // just use the name `this` uniformly diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 46c616ff36241..9169bc8809aa7 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -10,6 +10,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the /// span of that statement (including its semicolon, if any). /// The scope is used if a statement temporary must be dropped. + #[instrument(level = "debug", skip(self))] crate fn stmt_expr( &mut self, mut block: BasicBlock, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e6afc89baa03b..1a1c0485e35ca 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,3 +1,4 @@ +use crate::build::ExprCategory as Category; use crate::thir::cx::Cx; use crate::thir::util::UserAnnotatedTyHelpers; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -24,20 +25,26 @@ use rustc_target::abi::VariantIdx; impl<'tcx> Cx<'tcx> { crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId { // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow. - ensure_sufficient_stack(|| self.mirror_expr_inner(expr)) + ensure_sufficient_stack(|| self.mirror_expr_inner(expr, None)) } - crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { - exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() + crate fn mirror_exprs( + &mut self, + exprs: impl Iterator, Option>)>, + ) -> Box<[ExprId]> { + exprs.map(|(expr, ty)| self.mirror_expr_inner(expr, ty)).collect() } - pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId { + #[instrument(level = "debug", skip(self))] + pub(super) fn mirror_expr_inner( + &mut self, + hir_expr: &'tcx hir::Expr<'tcx>, + ty: Option>, + ) -> ExprId { let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id); let expr_scope = region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node }; - debug!("Expr::make_mirror(): id={}, span={:?}", hir_expr.hir_id, hir_expr.span); - let mut expr = self.make_mirror_unadjusted(hir_expr); let adjustment_span = match self.adjustment_span { @@ -47,12 +54,16 @@ impl<'tcx> Cx<'tcx> { // Now apply adjustments, if any. for adjustment in self.typeck_results.expr_adjustments(hir_expr) { - debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment); + debug!(?expr, ?adjustment); let span = expr.span; expr = self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span)); } + if !matches!(Category::of(&expr.kind), Some(Category::Constant)) { + expr.ty = ty.unwrap_or(expr.ty); + } + // Next, wrap this up in the expr's scope. expr = Expr { temp_lifetime, @@ -172,7 +183,7 @@ impl<'tcx> Cx<'tcx> { // is guaranteed to exist, since a method call always has a receiver. let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span)); tracing::info!("Using method span: {:?}", expr.span); - let args = self.mirror_exprs(args); + let args = self.mirror_exprs(args.iter().zip(std::iter::repeat(None))); self.adjustment_span = old_adjustment_span; ExprKind::Call { ty: expr.ty, @@ -194,12 +205,16 @@ impl<'tcx> Cx<'tcx> { let method = self.method_callee(expr, fun.span, None); - let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)); + let arg_tys: Vec<_> = + args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)).collect(); let tupled_args = Expr { - ty: self.tcx.mk_tup(arg_tys), + ty: self.tcx.mk_tup(arg_tys.iter()), temp_lifetime, span: expr.span, - kind: ExprKind::Tuple { fields: self.mirror_exprs(args) }, + kind: ExprKind::Tuple { + fields: self + .mirror_exprs(args.iter().zip(arg_tys.into_iter().map(Some))), + }, }; let tupled_args = self.thir.exprs.push(tupled_args); @@ -256,7 +271,7 @@ impl<'tcx> Cx<'tcx> { ExprKind::Call { ty: self.typeck_results().node_type(fun.hir_id), fun: self.mirror_expr(fun), - args: self.mirror_exprs(args), + args: self.mirror_exprs(args.iter().zip(std::iter::repeat(None))), from_hir_call: true, fn_span: expr.span, } @@ -763,10 +778,17 @@ impl<'tcx> Cx<'tcx> { ExprKind::Use { source: self.mirror_expr(source) } } hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) }, - hir::ExprKind::Array(ref fields) => { - ExprKind::Array { fields: self.mirror_exprs(fields) } - } - hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, + hir::ExprKind::Array(ref fields) => ExprKind::Array { + fields: self.mirror_exprs( + fields + .iter() + .zip(std::iter::repeat(Some(expr_ty.sequence_element_type(self.tcx)))), + ), + }, + hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { + fields: self + .mirror_exprs(fields.iter().zip(expr_ty.tuple_fields().iter().map(Some))), + }, hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr(v) }, hir::ExprKind::Err => unreachable!(), diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index cb32e88588af2..785538ab0df3d 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -356,7 +356,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let concrete_ty = tcx .mir_borrowck(owner) .concrete_opaque_types - .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id()) + .get(&def_id.to_def_id()) .copied() .map(|concrete| concrete.ty) .unwrap_or_else(|| { @@ -591,31 +591,17 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; debug!(?concrete_opaque_types); - for &(opaque_type_key, concrete_type) in concrete_opaque_types { - if opaque_type_key.def_id != self.def_id { + for &(def_id, concrete_type) in concrete_opaque_types { + if def_id != self.def_id { // Ignore constraints for other opaque types. continue; } - debug!(?concrete_type, ?opaque_type_key.substs, "found constraint"); + debug!(?concrete_type, "found constraint"); if let Some(prev) = self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() { - // Found different concrete types for the opaque type. - let mut err = self.tcx.sess.struct_span_err( - concrete_type.span, - "concrete type differs from previous defining opaque type use", - ); - err.span_label( - concrete_type.span, - format!("expected `{}`, got `{}`", prev.ty, concrete_type.ty), - ); - if prev.span == concrete_type.span { - err.span_label(prev.span, "this expression supplies two conflicting concrete types for the same opaque type"); - } else { - err.span_note(prev.span, "previous use here"); - } - err.emit(); + prev.report_mismatch(&concrete_type, self.tcx); } } else { self.found = Some(concrete_type); diff --git a/src/test/ui/impl-trait/issue-86465.stderr b/src/test/ui/impl-trait/issue-86465.stderr index 90d6904ed6164..bbc0a8fc60e53 100644 --- a/src/test/ui/impl-trait/issue-86465.stderr +++ b/src/test/ui/impl-trait/issue-86465.stderr @@ -1,11 +1,14 @@ error: concrete type differs from previous defining opaque type use - --> $DIR/issue-86465.rs:6:5 + --> $DIR/issue-86465.rs:6:9 | LL | (a, a) - | ^^^^^^ - | | - | expected `&'a u32`, got `&'b u32` - | this expression supplies two conflicting concrete types for the same opaque type + | ^ expected `&'a u32`, got `&'b u32` + | +note: previous use here + --> $DIR/issue-86465.rs:6:6 + | +LL | (a, a) + | ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr index 81e603e2355df..cf3897d37c61c 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr @@ -1,11 +1,14 @@ error: concrete type differs from previous defining opaque type use - --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 + --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:9 | LL | (i, i) - | ^^^^^^ - | | - | expected `&'a i32`, got `&'b i32` - | this expression supplies two conflicting concrete types for the same opaque type + | ^ expected `&'a i32`, got `&'b i32` + | +note: previous use here + --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:6 + | +LL | (i, i) + | ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr index 0f752212ac9c6..4af9bf8e0d3a0 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr @@ -1,11 +1,14 @@ error: concrete type differs from previous defining opaque type use - --> $DIR/multiple-def-uses-in-one-fn2.rs:10:5 + --> $DIR/multiple-def-uses-in-one-fn2.rs:10:17 | LL | (a.clone(), a) - | ^^^^^^^^^^^^^^ - | | - | expected `A`, got `B` - | this expression supplies two conflicting concrete types for the same opaque type + | ^ expected `A`, got `B` + | +note: previous use here + --> $DIR/multiple-def-uses-in-one-fn2.rs:10:6 + | +LL | (a.clone(), a) + | ^^^^^^^^^ error: aborting due to previous error