diff --git a/compiler/rustc_hir_analysis/src/check/writeback.rs b/compiler/rustc_hir_analysis/src/check/writeback.rs index 9aeee091fdd..e3e4a934ab5 100644 --- a/compiler/rustc_hir_analysis/src/check/writeback.rs +++ b/compiler/rustc_hir_analysis/src/check/writeback.rs @@ -560,13 +560,11 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { continue; } - let hidden_type = hidden_type - .remap_generic_params_to_declaration_params( - opaque_type_key, - self.fcx.infcx.tcx, - true, - ) - .ty; + let hidden_type = hidden_type.remap_generic_params_to_declaration_params( + opaque_type_key, + self.fcx.infcx.tcx, + true, + ); self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type); } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index ad9b124c8ab..0a69f965e75 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -564,6 +564,11 @@ struct ConstraintLocator<'tcx> { /// checked against it (we also carry the span of that first /// type). found: Option>, + + /// In the presence of dead code, typeck may figure out a hidden type + /// while borrowck will now. We collect these cases here and check at + /// the end that we actually found a type that matches (modulo regions). + typeck_types: Vec>, } impl ConstraintLocator<'_> { @@ -590,18 +595,23 @@ fn check(&mut self, item_def_id: LocalDefId) { self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() }); return; } - if !tables.concrete_opaque_types.contains_key(&self.def_id) { + let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else { debug!("no constraints in typeck results"); return; + }; + if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) { + self.typeck_types.push(typeck_hidden_ty); } + // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types; debug!(?concrete_opaque_types); if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) { debug!(?concrete_type, "found constraint"); - if let Some(prev) = self.found { - if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() { + if let Some(prev) = &mut self.found { + if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { prev.report_mismatch(&concrete_type, self.tcx); + prev.ty = self.tcx.ty_error(); } } else { self.found = Some(concrete_type); @@ -648,7 +658,7 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let scope = tcx.hir().get_defining_scope(hir_id); - let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None }; + let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None, typeck_types: vec![] }; debug!(?scope); @@ -678,16 +688,26 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { } } - match locator.found { - Some(hidden) => hidden.ty, - None => { - tcx.sess.emit_err(UnconstrainedOpaqueType { - span: tcx.def_span(def_id), - name: tcx.item_name(tcx.local_parent(def_id).to_def_id()), - }); - tcx.ty_error() + let Some(hidden) = locator.found else { + tcx.sess.emit_err(UnconstrainedOpaqueType { + span: tcx.def_span(def_id), + name: tcx.item_name(tcx.local_parent(def_id).to_def_id()), + }); + return tcx.ty_error(); + }; + + // Only check against typeck if we didn't already error + if !hidden.ty.references_error() { + for concrete_type in locator.typeck_types { + if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty) + && !(concrete_type, hidden).references_error() + { + hidden.report_mismatch(&concrete_type, tcx); + } } } + + hidden.ty } fn find_opaque_ty_constraints_for_rpit( @@ -788,7 +808,7 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { // the `concrete_opaque_types` table. tcx.ty_error() } else { - table.concrete_opaque_types.get(&def_id).copied().unwrap_or_else(|| { + table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| { // We failed to resolve the opaque type or it // resolves to itself. We interpret this as the // no values of the hidden type ever being constructed, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8277d141358..8a9160d2466 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -542,7 +542,7 @@ pub struct TypeckResults<'tcx> { /// by this function. We also store the /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, /// even if they are only set in dead code (which doesn't show up in MIR). - pub concrete_opaque_types: VecMap>, + pub concrete_opaque_types: VecMap>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs index 7740f774ebc..0b8157fe33d 100644 --- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.rs @@ -1,5 +1,5 @@ #![feature(type_alias_impl_trait)] -// check-pass + fn main() {} // two definitions with different types @@ -9,7 +9,7 @@ fn foo() -> Foo { "" } -fn bar() -> Foo { +fn bar() -> Foo { //~ ERROR: concrete type differs from previous defining opaque type use panic!() } diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr new file mode 100644 index 00000000000..09dadb0afce --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/different_defining_uses_never_type.rs:12:13 + | +LL | fn bar() -> Foo { + | ^^^ expected `&'static str`, got `()` + | +note: previous use here + --> $DIR/different_defining_uses_never_type.rs:9:5 + | +LL | "" + | ^^ + +error: aborting due to previous error +