diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index a7c4671665f43..56987edd1b6e3 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -2,12 +2,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; -use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::infer::{DefiningAnchor, InferCtxt}; use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine}; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts}; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable, @@ -16,8 +14,6 @@ use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::TraitEngineExt as _; -use crate::session_diagnostics::ConstNotUsedTraitAlias; - use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { @@ -229,31 +225,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { return self.tcx.ty_error(); } - let OpaqueTypeKey { def_id, substs } = opaque_type_key; - - // Use substs to build up a reverse map from regions to their - // identity mappings. This is necessary because of `impl - // Trait` lifetimes are computed by replacing existing - // lifetimes with 'static and remapping only those used in the - // `impl Trait` return type, resulting in the parameters - // shifting. - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); - debug!(?id_substs); - let map: FxHashMap, GenericArg<'tcx>> = - substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); - debug!("map = {:#?}", map); - - // Convert the type from the function into a type valid outside - // the function, by replacing invalid regions with 'static, - // after producing an error for each of them. - let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new( - self.tcx, - opaque_type_key, - map, - instantiated_ty.ty, - instantiated_ty.span, - )); - debug!(?definition_ty); + let definition_ty = instantiated_ty + .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) + .ty; if !check_opaque_type_parameter_valid( self.tcx, @@ -269,6 +243,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let OpaqueTyOrigin::TyAlias = origin else { return definition_ty; }; + let def_id = opaque_type_key.def_id; // This logic duplicates most of `check_opaque_meets_bounds`. // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. let param_env = self.tcx.param_env(def_id); @@ -284,6 +259,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { .to_predicate(infcx.tcx); let mut fulfillment_cx = >::new(infcx.tcx); + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); + // Require that the hidden type actually fulfills all the bounds of the opaque type, even without // the bounds that the function supplies. match infcx.register_hidden_type( @@ -424,221 +401,3 @@ fn check_opaque_type_parameter_valid( } true } - -struct ReverseMapper<'tcx> { - tcx: TyCtxt<'tcx>, - - key: ty::OpaqueTypeKey<'tcx>, - map: FxHashMap, GenericArg<'tcx>>, - do_not_error: bool, - - /// initially `Some`, set to `None` once error has been reported - hidden_ty: Option>, - - /// Span of function being checked. - span: Span, -} - -impl<'tcx> ReverseMapper<'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - key: ty::OpaqueTypeKey<'tcx>, - map: FxHashMap, GenericArg<'tcx>>, - hidden_ty: Ty<'tcx>, - span: Span, - ) -> Self { - Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span } - } - - fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.do_not_error); - self.do_not_error = true; - let kind = kind.fold_with(self); - self.do_not_error = false; - kind - } - - fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.do_not_error); - kind.fold_with(self) - } -} - -impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - #[instrument(skip(self), level = "debug")] - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - // Ignore bound regions and `'static` regions that appear in the - // type, we only need to remap regions that reference lifetimes - // from the function declaration. - // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. - ty::ReLateBound(..) | ty::ReStatic => return r, - - // If regions have been erased (by writeback), don't try to unerase - // them. - ty::ReErased => return r, - - // The regions that we expect from borrow checking. - ty::ReEarlyBound(_) | ty::ReFree(_) => {} - - ty::RePlaceholder(_) | ty::ReVar(_) => { - // All of the regions in the type should either have been - // erased by writeback, or mapped back to named regions by - // borrow checking. - bug!("unexpected region kind in opaque type: {:?}", r); - } - } - - let generics = self.tcx().generics_of(self.key.def_id); - match self.map.get(&r.into()).map(|k| k.unpack()) { - Some(GenericArgKind::Lifetime(r1)) => r1, - Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None if self.do_not_error => self.tcx.lifetimes.re_static, - None if generics.parent.is_some() => { - if let Some(hidden_ty) = self.hidden_ty.take() { - unexpected_hidden_region_diagnostic( - self.tcx, - self.tcx.def_span(self.key.def_id), - hidden_ty, - r, - self.key, - ) - .emit(); - } - self.tcx.lifetimes.re_static - } - None => { - self.tcx - .sess - .struct_span_err(self.span, "non-defining opaque type use in defining scope") - .span_label( - self.span, - format!( - "lifetime `{}` is part of concrete type but not used in \ - parameter list of the `impl Trait` type alias", - r - ), - ) - .emit(); - - self.tcx().lifetimes.re_static - } - } - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Closure(def_id, substs) => { - // I am a horrible monster and I pray for death. When - // we encounter a closure here, it is always a closure - // from within the function that we are currently - // type-checking -- one that is now being encapsulated - // in an opaque type. Ideally, we would - // go through the types/lifetimes that it references - // and treat them just like we would any other type, - // which means we would error out if we find any - // reference to a type/region that is not in the - // "reverse map". - // - // **However,** in the case of closures, there is a - // somewhat subtle (read: hacky) consideration. The - // problem is that our closure types currently include - // all the lifetime parameters declared on the - // enclosing function, even if they are unused by the - // closure itself. We can't readily filter them out, - // so here we replace those values with `'empty`. This - // can't really make a difference to the rest of the - // compiler; those regions are ignored for the - // outlives relation, and hence don't affect trait - // selection or auto traits, and they are erased - // during codegen. - - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_no_missing_regions_error(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_closure(def_id, substs) - } - - ty::Generator(def_id, substs, movability) => { - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_no_missing_regions_error(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_generator(def_id, substs, movability) - } - - ty::Param(param) => { - // Look it up in the substitution list. - match self.map.get(&ty.into()).map(|k| k.unpack()) { - // Found it in the substitution list; replace with the parameter from the - // opaque type. - Some(GenericArgKind::Type(t1)) => t1, - Some(u) => panic!("type mapped to unexpected kind: {:?}", u), - None => { - debug!(?param, ?self.map); - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "type parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ty - ), - ) - .emit(); - - self.tcx().ty_error() - } - } - } - - _ => ty.super_fold_with(self), - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - trace!("checking const {:?}", ct); - // Find a const parameter - match ct.kind() { - ty::ConstKind::Param(..) => { - // Look it up in the substitution list. - match self.map.get(&ct.into()).map(|k| k.unpack()) { - // Found it in the substitution list, replace with the parameter from the - // opaque type. - Some(GenericArgKind::Const(c1)) => c1, - Some(u) => panic!("const mapped to unexpected kind: {:?}", u), - None => { - self.tcx.sess.emit_err(ConstNotUsedTraitAlias { - ct: ct.to_string(), - span: self.span, - }); - - self.tcx().const_error(ct.ty()) - } - } - } - - _ => ct, - } - } -} diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 9f19453a1a658..ff667896eb107 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -52,15 +52,6 @@ pub(crate) struct VarNeedNotMut { #[suggestion_short(applicability = "machine-applicable", code = "")] pub span: Span, } - -#[derive(Diagnostic)] -#[diag(borrowck::const_not_used_in_type_alias)] -pub(crate) struct ConstNotUsedTraitAlias { - pub ct: String, - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(borrowck::var_cannot_escape_closure)] #[note] diff --git a/compiler/rustc_hir_analysis/src/check/writeback.rs b/compiler/rustc_hir_analysis/src/check/writeback.rs index 3583769b7cd64..e3e4a934ab563 100644 --- a/compiler/rustc_hir_analysis/src/check/writeback.rs +++ b/compiler/rustc_hir_analysis/src/check/writeback.rs @@ -536,33 +536,36 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let opaque_types = self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); for (opaque_type_key, decl) in opaque_types { - let hidden_type = match decl.origin { - hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { - let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span); - struct RecursionChecker { - def_id: LocalDefId, - } - impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker { - type BreakTy = (); - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if let ty::Opaque(def_id, _) = *t.kind() { - if def_id == self.def_id.to_def_id() { - return ControlFlow::Break(()); - } - } - t.super_visit_with(self) + let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span); + let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span); + + struct RecursionChecker { + def_id: LocalDefId, + } + impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + if let ty::Opaque(def_id, _) = *t.kind() { + if def_id == self.def_id.to_def_id() { + return ControlFlow::Break(()); } } - if ty - .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id }) - .is_break() - { - return; - } - Some(ty) + t.super_visit_with(self) } - hir::OpaqueTyOrigin::TyAlias => None, - }; + } + if hidden_type + .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id }) + .is_break() + { + 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); } } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index f8a62c8491076..0a69f965e751d 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 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T /// 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 find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T 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 find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T 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 find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T } } - 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,20 +808,15 @@ fn find_opaque_ty_constraints_for_rpit( // the `concrete_opaque_types` table. tcx.ty_error() } else { - table - .concrete_opaque_types - .get(&def_id) - .copied() - .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. - Some(tcx.mk_diverging_default()) - }) - .expect("RPIT always have a hidden type from typeck") + 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() + }) } }) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 97646003e7339..8a9160d246640 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -539,12 +539,10 @@ pub struct TypeckResults<'tcx> { pub tainted_by_errors: Option, /// All the opaque types that have hidden types set - /// by this function. For return-position-impl-trait we also store the - /// type here, so that mir-borrowck can figure out hidden types, + /// 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). - /// For type-alias-impl-trait, this map is only used to prevent query cycles, - /// so the hidden types are all `None`. - 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/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 855917fb82869..ffade628e53b5 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -511,3 +511,11 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { c.super_visit_with(self) } } + +#[derive(Diagnostic)] +#[diag(borrowck::const_not_used_in_type_alias)] +pub(super) struct ConstNotUsedTraitAlias { + pub ct: String, + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 753d7bffe84c2..cb7700f9bcab4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -131,6 +131,7 @@ mod generics; mod impls_ty; mod instance; mod list; +mod opaque_types; mod parameterized; mod rvalue_scopes; mod structural_impls; @@ -1300,6 +1301,34 @@ impl<'tcx> OpaqueHiddenType<'tcx> { sub: sub_diag, }); } + + #[instrument(level = "debug", skip(tcx), ret)] + pub fn remap_generic_params_to_declaration_params( + self, + opaque_type_key: OpaqueTypeKey<'tcx>, + tcx: TyCtxt<'tcx>, + // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck. + ignore_errors: bool, + ) -> Self { + let OpaqueTypeKey { def_id, substs } = opaque_type_key; + + // Use substs to build up a reverse map from regions to their + // identity mappings. This is necessary because of `impl + // Trait` lifetimes are computed by replacing existing + // lifetimes with 'static and remapping only those used in the + // `impl Trait` return type, resulting in the parameters + // shifting. + let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + debug!(?id_substs); + let map: FxHashMap, GenericArg<'tcx>> = + substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); + debug!("map = {:#?}", map); + + // Convert the type from the function into a type valid outside + // the function, by replacing invalid regions with 'static, + // after producing an error for each of them. + self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors)) + } } /// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs new file mode 100644 index 0000000000000..b05c6310929b5 --- /dev/null +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -0,0 +1,218 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_span::Span; + +/// Converts generic params of a TypeFoldable from one +/// item's generics to another. Usually from a function's generics +/// list to the opaque type's own generics. +pub(super) struct ReverseMapper<'tcx> { + tcx: TyCtxt<'tcx>, + map: FxHashMap, GenericArg<'tcx>>, + /// see call sites to fold_kind_no_missing_regions_error + /// for an explanation of this field. + do_not_error: bool, + + /// We do not want to emit any errors in typeck because + /// the spans in typeck are subpar at the moment. + /// Borrowck will do the same work again (this time with + /// lifetime information) and thus report better errors. + ignore_errors: bool, + + /// Span of function being checked. + span: Span, +} + +impl<'tcx> ReverseMapper<'tcx> { + pub(super) fn new( + tcx: TyCtxt<'tcx>, + map: FxHashMap, GenericArg<'tcx>>, + span: Span, + ignore_errors: bool, + ) -> Self { + Self { tcx, map, do_not_error: false, ignore_errors, span } + } + + fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { + assert!(!self.do_not_error); + self.do_not_error = true; + let kind = kind.fold_with(self); + self.do_not_error = false; + kind + } + + fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { + assert!(!self.do_not_error); + kind.fold_with(self) + } +} + +impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + #[instrument(skip(self), level = "debug")] + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + // Ignore bound regions and `'static` regions that appear in the + // type, we only need to remap regions that reference lifetimes + // from the function declaration. + // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. + ty::ReLateBound(..) | ty::ReStatic => return r, + + // If regions have been erased (by writeback), don't try to unerase + // them. + ty::ReErased => return r, + + // The regions that we expect from borrow checking. + ty::ReEarlyBound(_) | ty::ReFree(_) => {} + + ty::RePlaceholder(_) | ty::ReVar(_) => { + // All of the regions in the type should either have been + // erased by writeback, or mapped back to named regions by + // borrow checking. + bug!("unexpected region kind in opaque type: {:?}", r); + } + } + + match self.map.get(&r.into()).map(|k| k.unpack()) { + Some(GenericArgKind::Lifetime(r1)) => r1, + Some(u) => panic!("region mapped to unexpected kind: {:?}", u), + None if self.do_not_error => self.tcx.lifetimes.re_static, + None => { + self.tcx + .sess + .struct_span_err(self.span, "non-defining opaque type use in defining scope") + .span_label( + self.span, + format!( + "lifetime `{}` is part of concrete type but not used in \ + parameter list of the `impl Trait` type alias", + r + ), + ) + .emit(); + + self.tcx().lifetimes.re_static + } + } + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Closure(def_id, substs) => { + // I am a horrible monster and I pray for death. When + // we encounter a closure here, it is always a closure + // from within the function that we are currently + // type-checking -- one that is now being encapsulated + // in an opaque type. Ideally, we would + // go through the types/lifetimes that it references + // and treat them just like we would any other type, + // which means we would error out if we find any + // reference to a type/region that is not in the + // "reverse map". + // + // **However,** in the case of closures, there is a + // somewhat subtle (read: hacky) consideration. The + // problem is that our closure types currently include + // all the lifetime parameters declared on the + // enclosing function, even if they are unused by the + // closure itself. We can't readily filter them out, + // so here we replace those values with `'empty`. This + // can't really make a difference to the rest of the + // compiler; those regions are ignored for the + // outlives relation, and hence don't affect trait + // selection or auto traits, and they are erased + // during codegen. + + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_no_missing_regions_error(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })); + + self.tcx.mk_closure(def_id, substs) + } + + ty::Generator(def_id, substs, movability) => { + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_no_missing_regions_error(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })); + + self.tcx.mk_generator(def_id, substs, movability) + } + + ty::Param(param) => { + // Look it up in the substitution list. + match self.map.get(&ty.into()).map(|k| k.unpack()) { + // Found it in the substitution list; replace with the parameter from the + // opaque type. + Some(GenericArgKind::Type(t1)) => t1, + Some(u) => panic!("type mapped to unexpected kind: {:?}", u), + None => { + debug!(?param, ?self.map); + if !self.ignore_errors { + self.tcx + .sess + .struct_span_err( + self.span, + &format!( + "type parameter `{}` is part of concrete type but not \ + used in parameter list for the `impl Trait` type alias", + ty + ), + ) + .emit(); + } + + self.tcx().ty_error() + } + } + } + + _ => ty.super_fold_with(self), + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + trace!("checking const {:?}", ct); + // Find a const parameter + match ct.kind() { + ty::ConstKind::Param(..) => { + // Look it up in the substitution list. + match self.map.get(&ct.into()).map(|k| k.unpack()) { + // Found it in the substitution list, replace with the parameter from the + // opaque type. + Some(GenericArgKind::Const(c1)) => c1, + Some(u) => panic!("const mapped to unexpected kind: {:?}", u), + None => { + if !self.ignore_errors { + self.tcx.sess.emit_err(ty::ConstNotUsedTraitAlias { + ct: ct.to_string(), + span: self.span, + }); + } + + self.tcx().const_error(ct.ty()) + } + } + } + + _ => ct, + } + } +} diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index 076eddaabc048..3ff949fbb3f80 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -323,7 +323,7 @@ pub fn change_return_impl_trait() -> impl Clone { #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail5", except = "typeck")] #[rustc_clean(cfg = "cfail6")] pub fn change_return_impl_trait() -> impl Copy { 0u32 diff --git a/src/test/ui/impl-trait/issues/issue-86800.stderr b/src/test/ui/impl-trait/issues/issue-86800.stderr index 135d06d44adae..6c4aa35679d5b 100644 --- a/src/test/ui/impl-trait/issues/issue-86800.stderr +++ b/src/test/ui/impl-trait/issues/issue-86800.stderr @@ -1,3 +1,11 @@ +error: unconstrained opaque type + --> $DIR/issue-86800.rs:33:34 + | +LL | type TransactionFuture<'__, O> = impl '__ + Future>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = + stack backtrace: @@ -12,8 +20,7 @@ error: internal compiler error: unexpected panic query stack during panic: -#0 [mir_borrowck] borrow-checking `execute_transaction_fut` -#1 [type_of] computing type of `TransactionFuture::{opaque#0}` -#2 [check_mod_item_types] checking item types in top-level module -#3 [analysis] running analysis passes on this crate +#0 [type_of] computing type of `TransactionFuture::{opaque#0}` +#1 [check_mod_item_types] checking item types in top-level module +#2 [analysis] running analysis passes on this crate end of query stack 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 7740f774ebca4..0b8157fe33dd7 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 0000000000000..09dadb0afcef5 --- /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 + diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type3.rs b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type3.rs new file mode 100644 index 0000000000000..bc827a8f2113a --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type3.rs @@ -0,0 +1,12 @@ +#![feature(type_alias_impl_trait)] + +type Tait = impl Sized; + +struct One; +fn one() -> Tait { One } + +struct Two(T); +fn two() -> Tait { Two::<()>(todo!()) } +//~^ ERROR concrete type differs from previous defining opaque type use + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type3.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type3.stderr new file mode 100644 index 0000000000000..146a57cbb7e05 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type3.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/different_defining_uses_never_type3.rs:9:13 + | +LL | fn two() -> Tait { Two::<()>(todo!()) } + | ^^^^ expected `One`, got `Two<()>` + | +note: previous use here + --> $DIR/different_defining_uses_never_type3.rs:6:20 + | +LL | fn one() -> Tait { One } + | ^^^ + +error: aborting due to previous error +