diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 6c7c2b9eea258..1144cf41d9b08 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -569,12 +569,17 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) }); return; } - let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else { + + let mut constrained_during_typeck = false; + for (key, typeck_hidden_ty) in &tables.concrete_opaque_types { + if key.def_id == self.def_id { + constrained_during_typeck = true; + self.typeck_types.push(*typeck_hidden_ty); + } + } + if !constrained_during_typeck { 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. @@ -678,10 +683,11 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T // 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) + if concrete_type.ty != tcx.erase_regions(hidden.ty) && !(concrete_type, hidden).references_error() { - hidden.report_mismatch(&concrete_type, tcx); + let reported = hidden.report_mismatch(&concrete_type, tcx); + return tcx.ty_error(reported); } } } @@ -786,15 +792,24 @@ fn find_opaque_ty_constraints_for_rpit( // the `concrete_opaque_types` table. tcx.ty_error(guar) } 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, - // so we can just make the hidden type be `!`. - // For backwards compatibility reasons, we fall back to - // `()` until we the diverging default is changed. - tcx.mk_diverging_default() - }) + table + .concrete_opaque_types + .iter() + .find(|(key, _)| { + // For backwards compatibility, we choose the first matching + // opaque type definition + key.def_id == 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, + // so we can just make the hidden type be `!`. + // For backwards compatibility reasons, we fall back to + // `()` until we the diverging default is changed. + tcx.mk_diverging_default() + }) } }) } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 59bee69cfffac..a62feec727e6e 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -579,13 +579,22 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { continue; } - 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); + let hidden_type = + self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params( + opaque_type_key, + self.fcx.infcx.tcx, + true, + )); + + if let Some(last_opaque_ty) = + self.typeck_results.concrete_opaque_types.insert(opaque_type_key, hidden_type) + { + if last_opaque_ty.ty != self.tcx().erase_regions(hidden_type.ty) + && !(last_opaque_ty, hidden_type).references_error() + { + hidden_type.report_mismatch(&last_opaque_ty, self.tcx()); + } + } } } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 5a0571f4bb7cb..dece251e80fff 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -155,7 +155,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: FxIndexMap>, + pub concrete_opaque_types: FxIndexMap, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs new file mode 100644 index 0000000000000..e5bfbfdae91fd --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +type Tait<'a> = impl Sized + 'a; + +fn foo<'a, 'b>() { + if false { + if { return } { + let y: Tait<'b> = 1i32; + //~^ ERROR concrete type differs from previous defining opaque type use + } + } + let x: Tait<'a> = (); +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr new file mode 100644 index 0000000000000..f2eb7bc4dc79b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/different_defining_uses_never_type-2.rs:8:31 + | +LL | let y: Tait<'b> = 1i32; + | ^^^^ expected `()`, got `i32` + | +note: previous use here + --> $DIR/different_defining_uses_never_type-2.rs:12:23 + | +LL | let x: Tait<'a> = (); + | ^^ + +error: aborting due to previous error +