From ea9517ef8b0d35ba0c893743a96f30338d603a0a Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sat, 17 Sep 2022 21:35:47 +0300 Subject: [PATCH 1/9] don't normalize in astconv We delay projection normalization to further stages in order to register user type annotations before normalization in HIR typeck. There are two consumers of astconv: ItemCtxt and FnCtxt. The former already expects unnormalized types from astconv, see its AstConv trait impl. The latter needs `RawTy` for a cleaner interface. Unfortunately astconv still needs the normalization machinery in order to resolve enum variants that have projections in the self type, e.g. `<::Assoc>::StructVariant {}`. This is why `AstConv::normalize_ty_2` is necessary. --- .../rustc_hir_analysis/src/astconv/mod.rs | 36 ++--- compiler/rustc_hir_analysis/src/collect.rs | 5 - compiler/rustc_hir_typeck/src/closure.rs | 6 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 70 +++++---- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 32 ++-- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 20 ++- .../rustc_hir_typeck/src/gather_locals.rs | 5 +- compiler/rustc_hir_typeck/src/lib.rs | 2 +- .../rustc_hir_typeck/src/method/confirm.rs | 8 +- compiler/rustc_hir_typeck/src/pat.rs | 4 +- compiler/rustc_traits/src/type_op.rs | 1 + src/test/ui/const-generics/issue-97007.rs | 6 +- .../generic-associated-types/issue-91139.rs | 8 - .../issue-91139.stderr | 61 +------- .../normalize-under-binder/issue-85455.rs | 1 + .../normalize-under-binder/issue-85455.stderr | 13 +- ...malformed-projection-input-issue-102800.rs | 12 +- ...ormed-projection-input-issue-102800.stderr | 86 +---------- .../nll/user-annotations/ascribed-type-wf.rs | 5 +- .../user-annotations/ascribed-type-wf.stderr | 10 ++ .../user-annotations/dump-adt-brace-struct.rs | 2 + .../dump-adt-brace-struct.stderr | 18 ++- .../nll/user-annotations/normalization-2.rs | 80 ++++++++++ .../user-annotations/normalization-2.stderr | 141 ++++++++++++++++++ .../ui/ufcs/ufcs-partially-resolved.stderr | 2 +- 25 files changed, 380 insertions(+), 254 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/ascribed-type-wf.stderr create mode 100644 src/test/ui/nll/user-annotations/normalization-2.rs create mode 100644 src/test/ui/nll/user-annotations/normalization-2.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index e744ed2dcc547..f65ad2534fc77 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -108,8 +108,9 @@ pub trait AstConv<'tcx> { poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx>; - /// Normalize an associated type coming from the user. - fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; + fn normalize_ty_2(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + ty + } /// Invoked when we encounter an error from some prior pass /// (e.g., resolve) that is translated into a ty-error. This is @@ -484,12 +485,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Avoid ICE #86756 when type error recovery goes awry. return tcx.ty_error().into(); } - self.astconv - .normalize_ty( - self.span, - EarlyBinder(tcx.at(self.span).type_of(param.def_id)) - .subst(tcx, substs), - ) + EarlyBinder(tcx.at(self.span).type_of(param.def_id)) + .subst(tcx, substs) .into() } else if infer_args { self.astconv.ty_infer(Some(param), self.span).into() @@ -1254,10 +1251,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment: &hir::PathSegment<'_>, ) -> Ty<'tcx> { let substs = self.ast_path_substs_for_ty(span, did, item_segment); - self.normalize_ty( - span, - EarlyBinder(self.tcx().at(span).type_of(did)).subst(self.tcx(), substs), - ) + EarlyBinder(self.tcx().at(span).type_of(did)).subst(self.tcx(), substs) } fn conv_object_ty_poly_trait_ref( @@ -1789,7 +1783,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Ok(bound) } - // Create a type from a path to an associated type. + // Create a type from a path to an associated type or to an enum variant. // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C` // and item_segment is the path segment for `D`. We return a type and a def for // the whole path. @@ -1817,7 +1811,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Check if we have an enum variant. let mut variant_resolution = None; - if let ty::Adt(adt_def, _) = qself_ty.kind() { + if let ty::Adt(adt_def, _) = self.normalize_ty_2(span, qself_ty).kind() { if adt_def.is_enum() { let variant_def = adt_def .variants() @@ -2017,7 +2011,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound); - let ty = self.normalize_ty(span, ty); if let Some(variant_def_id) = variant_resolution { tcx.struct_span_lint_hir( @@ -2153,7 +2146,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("qpath_to_ty: trait_ref={:?}", trait_ref); - self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs)) + tcx.mk_projection(item_def_id, item_substs) } pub fn prohibit_generics<'a>( @@ -2391,6 +2384,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Check a type `Path` and convert it to a `Ty`. + // If the path is an enum variant the returned type is the type of the enum. pub fn res_to_ty( &self, opt_self_ty: Option>, @@ -2414,7 +2408,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.note("`impl Trait` types can't have type parameters"); }); let substs = self.ast_path_substs_for_ty(span, did, item_segment.0); - self.normalize_ty(span, tcx.mk_opaque(did, substs)) + tcx.mk_opaque(did, substs) } Res::Def( DefKind::Enum @@ -2574,7 +2568,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } tcx.ty_error_with_guaranteed(err.emit()) } else { - self.normalize_ty(span, ty) + ty } } Res::Def(DefKind::AssocTy, def_id) => { @@ -2717,8 +2711,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { None, ty::BoundConstness::NotConst, ); - EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id))) - .subst(tcx, substs) + EarlyBinder(tcx.at(span).type_of(def_id)).subst(tcx, substs) } hir::TyKind::Array(ref ty, ref length) => { let length = match length { @@ -2728,8 +2721,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }; - let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length)); - self.normalize_ty(ast_ty.span, array_ty) + tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length)) } hir::TyKind::Typeof(ref e) => { let ty_erased = tcx.type_of(e.def_id); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index a738ee4a14887..4641421add958 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -513,11 +513,6 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } } - fn normalize_ty(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - // Types in item signatures are not normalized to avoid undue dependencies. - ty - } - fn set_tainted_by_errors(&self, _: ErrorGuaranteed) { // There's no obvious place to track this, so just let it go. } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 6cf9e23b40b0e..e78310e0f24aa 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -621,14 +621,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), bound_vars, ); - // Astconv can't normalize inputs or outputs with escaping bound vars, - // so normalize them here, after we've wrapped them in a binder. - let result = self.normalize_associated_types_in(self.tcx.hir().span(hir_id), result); let c_result = self.inh.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); - result + // Normalize only after registering in `user_provided_sigs`. + self.normalize_associated_types_in(self.tcx.hir().span(hir_id), result) } /// Invoked when we are translating the generator that results diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index b85a23257286b..97cf5c91d31e8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,7 +1,7 @@ use crate::callee::{self, DeferredCallResolution}; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; -use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy}; +use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; @@ -464,23 +464,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { + pub fn create_raw_ty(&self, span: Span, ty: Ty<'tcx>) -> RawTy<'tcx> { + RawTy { raw: ty, normalized: self.normalize_associated_types_in(span, ty) } + } + + pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> RawTy<'tcx> { let t = >::ast_ty_to_ty(self, ast_t); self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None)); - t + self.create_raw_ty(ast_t.span, t) } pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { let ty = self.to_ty(ast_ty); debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); - if Self::can_contain_user_lifetime_bounds(ty) { - let c_ty = self.canonicalize_response(UserType::Ty(ty)); + if Self::can_contain_user_lifetime_bounds(ty.raw) { + let c_ty = self.canonicalize_response(UserType::Ty(ty.raw)); debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); } - ty + ty.normalized } pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> { @@ -831,7 +835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &'tcx QPath<'tcx>, hir_id: hir::HirId, span: Span, - ) -> (Res, Option>, &'tcx [hir::PathSegment<'tcx>]) { + ) -> (Res, Option>, &'tcx [hir::PathSegment<'tcx>]) { debug!( "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span @@ -854,7 +858,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to be object-safe. // We manually call `register_wf_obligation` in the success path // below. - (>::ast_ty_to_ty_in_path(self, qself), qself, segment) + let ty = >::ast_ty_to_ty_in_path(self, qself); + (self.create_raw_ty(span, ty), qself, segment) } QPath::LangItem(..) => { bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`") @@ -862,7 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) { - self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); + self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None)); // Return directly on cache hit. This is useful to avoid doubly reporting // errors with default match binding modes. See #44614. let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)); @@ -870,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let item_name = item_segment.ident; let result = self - .resolve_fully_qualified_call(span, item_name, ty, qself.span, hir_id) + .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id) .or_else(|error| { let result = match error { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), @@ -881,13 +886,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise, // register a WF obligation so that we can detect any additional // errors in the self type. - if !(matches!(error, method::MethodError::NoMatch(_)) && ty.is_trait()) { - self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); + if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) { + self.register_wf_obligation( + ty.raw.into(), + qself.span, + traits::WellFormed(None), + ); } if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, - ty, + ty.normalized, item_name, SelfSource::QPath(qself), error, @@ -900,7 +909,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if result.is_ok() { - self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); + self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None)); } // Write back the new resolution. @@ -1037,17 +1046,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn instantiate_value_path( &self, segments: &[hir::PathSegment<'_>], - self_ty: Option>, + self_ty: Option>, res: Res, span: Span, hir_id: hir::HirId, ) -> (Ty<'tcx>, Res) { let tcx = self.tcx; + assert_eq!(res.ns(), Some(rustc_hir::def::Namespace::ValueNS)); let path_segs = match res { Res::Local(_) | Res::SelfCtor(_) => vec![], Res::Def(kind, def_id) => >::def_ids_for_value_path_segments( - self, segments, self_ty, kind, def_id, + self, + segments, + self_ty.map(|ty| ty.normalized), + kind, + def_id, ), _ => bug!("instantiate_value_path on {:?}", res), }; @@ -1058,8 +1072,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) if let Some(self_ty) = self_ty => { - let adt_def = self_ty.ty_adt_def().unwrap(); - user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty }); + let adt_def = self_ty.normalized.ty_adt_def().unwrap(); + user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw }); is_alias_variant_ctor = true; } Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { @@ -1078,7 +1092,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // inherent impl, we need to record the // `T` for posterity (see `UserSelfTy` for // details). - let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); + let self_ty = self_ty.expect("UFCS sugared assoc missing Self").raw; user_self_ty = Some(UserSelfTy { impl_def_id: container_id, self_ty }); } } @@ -1160,7 +1174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(false); let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { - let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); + let ty = self.normalize_ty_2(span, tcx.at(span).type_of(impl_def_id)); match *ty.kind() { ty::Adt(adt_def, substs) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant(); @@ -1251,7 +1265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { >::ast_region_to_region(self.fcx, lt, Some(param)).into() } (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - self.fcx.to_ty(ty).into() + self.fcx.to_ty(ty).raw.into() } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { self.fcx.const_arg_to_const(&ct.value, param.def_id).into() @@ -1285,7 +1299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // is missing. let default = tcx.bound_type_of(param.def_id); self.fcx - .normalize_ty(self.span, default.subst(tcx, substs.unwrap())) + .normalize_ty_2(self.span, default.subst(tcx, substs.unwrap())) .into() } else { // If no type arguments were provided, we have to infer them. @@ -1308,13 +1322,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let substs = self_ctor_substs.unwrap_or_else(|| { + let substs_raw = self_ctor_substs.unwrap_or_else(|| { >::create_substs_for_generic_args( tcx, def_id, &[], has_self, - self_ty, + self_ty.map(|s| s.raw), &arg_count, &mut CreateCtorSubstsContext { fcx: self, @@ -1325,11 +1339,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ) }); - assert!(!substs.has_escaping_bound_vars()); + assert!(!substs_raw.has_escaping_bound_vars()); assert!(!ty.has_escaping_bound_vars()); // First, store the "user substs" for later. - self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); + self.write_user_type_annotation_from_substs(hir_id, def_id, substs_raw, user_self_ty); + + // Normalize only after registering type annotations. + let substs = self.normalize_associated_types_in(span, substs_raw); self.add_required_obligations_for_hir(span, def_id, &substs, hir_id); @@ -1346,6 +1363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = tcx.type_of(impl_def_id); let impl_ty = self.instantiate_type_scheme(span, &substs, ty); + let self_ty = self.normalize_associated_types_in(span, self_ty); match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a31ab9c8b23b8..b1b4e21e10dfe 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -5,7 +5,7 @@ use crate::method::MethodCallee; use crate::Expectation::*; use crate::TupleArgumentsFlag::*; use crate::{ - struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, + struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy, TupleArgumentsFlag, }; use rustc_ast as ast; @@ -1215,13 +1215,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return None; } - Res::Def(DefKind::Variant, _) => match ty.kind() { + Res::Def(DefKind::Variant, _) => match ty.normalized.kind() { ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did(), substs)), - _ => bug!("unexpected type: {:?}", ty), + _ => bug!("unexpected type: {:?}", ty.normalized), }, Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | Res::SelfTyParam { .. } - | Res::SelfTyAlias { .. } => match ty.kind() { + | Res::SelfTyAlias { .. } => match ty.normalized.kind() { ty::Adt(adt, substs) if !adt.is_enum() => { Some((adt.non_enum_variant(), adt.did(), substs)) } @@ -1232,14 +1232,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some((variant, did, substs)) = variant { debug!("check_struct_path: did={:?} substs={:?}", did, substs); - self.write_user_type_annotation_from_substs(hir_id, did, substs, None); + + // FIXME(aliemjay): We're using UserSelfTy unconditionally here because it is the only + // way to register the raw user ty, because `substs` is normalized. + let self_ty = ty::UserSelfTy { impl_def_id: did, self_ty: ty.raw }; + self.write_user_type_annotation_from_substs(hir_id, did, substs, Some(self_ty)); // Check bounds on type arguments used in the path. self.add_required_obligations_for_hir(path_span, did, substs, hir_id); - Some((variant, ty)) + Some((variant, ty.normalized)) } else { - match ty.kind() { + match ty.normalized.kind() { ty::Error(_) => { // E0071 might be caused by a spelling error, which will have // already caused an error message and probably a suggestion @@ -1252,7 +1256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { path_span, E0071, "expected struct, variant or union type, found {}", - ty.sort_string(self.tcx) + ty.normalized.sort_string(self.tcx) ) .span_label(path_span, "not a struct") .emit(); @@ -1643,20 +1647,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &QPath<'_>, path_span: Span, hir_id: hir::HirId, - ) -> (Res, Ty<'tcx>) { + ) -> (Res, RawTy<'tcx>) { match *qpath { QPath::Resolved(ref maybe_qself, ref path) => { - let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); + let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw); let ty = >::res_to_ty(self, self_ty, path, true); - (path.res, ty) + (path.res, self.create_raw_ty(path_span, ty)) } QPath::TypeRelative(ref qself, ref segment) => { let ty = self.to_ty(qself); let result = >::associated_path_to_ty( - self, hir_id, path_span, ty, qself, segment, true, + self, hir_id, path_span, ty.raw, qself, segment, true, ); let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); + let ty = self.create_raw_ty(path_span, ty); let result = result.map(|(_, kind, def_id)| (kind, def_id)); // Write back the new resolution. @@ -1665,7 +1670,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) } QPath::LangItem(lang_item, span, id) => { - self.resolve_lang_item_path(lang_item, span, hir_id, id) + let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id); + (res, self.create_raw_ty(path_span, ty)) } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 177d521d2804c..99dfaef0f8f78 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -17,7 +17,6 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::symbol::Ident; @@ -282,7 +281,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.tcx().mk_projection(item_def_id, item_substs) } - fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + fn normalize_ty_2(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + use rustc_middle::ty::TypeVisitable; if ty.has_escaping_bound_vars() { ty // FIXME: normalization and escaping regions } else { @@ -294,7 +294,19 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.infcx.set_tainted_by_errors(e) } - fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { - self.write_ty(hir_id, ty) + fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) { + self.write_ty(hir_id, self.normalize_ty_2(span, ty)) } } + +/// Represents a user-provided type in the raw form (never normalized). +/// +/// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`, +/// and the API in this module, which expect `Ty` to be fully normalized. +#[derive(Clone, Copy, Debug)] +pub struct RawTy<'tcx> { + pub raw: Ty<'tcx>, + + /// The normalized form of `raw`, stored here for efficiency. + pub normalized: Ty<'tcx>, +} diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 9a096f24fac0d..15dd3412c3409 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -77,7 +77,8 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { Some(ref ty) => { let o_ty = self.fcx.to_ty(&ty); - let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty)); + let c_ty = + self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw)); debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); self.fcx .typeck_results @@ -85,7 +86,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { .user_provided_types_mut() .insert(ty.hir_id, c_ty); - Some(LocalTy { decl_ty: o_ty, revealed_ty: o_ty }) + Some(LocalTy { decl_ty: o_ty.normalized, revealed_ty: o_ty.normalized }) } None => None, }; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 334d6d0aa6c20..e3745a20dbf12 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -338,7 +338,7 @@ fn typeck_with_fallback<'tcx>( fcx.resolve_generator_interiors(def_id.to_def_id()); for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { - let ty = fcx.normalize_ty(span, ty); + let ty = fcx.normalize_associated_types_in(span, ty); fcx.require_type_is_sized(ty, span, code); } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index d996d6ec610ba..0a20c09666685 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { .into() } (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - self.cfcx.to_ty(ty).into() + self.cfcx.to_ty(ty).raw.into() } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { self.cfcx.const_arg_to_const(&ct.value, param.def_id).into() @@ -400,7 +400,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.cfcx.var_for_def(self.cfcx.span, param) } } - >::create_substs_for_generic_args( + let substs = >::create_substs_for_generic_args( self.tcx, pick.item.def_id, parent_substs, @@ -408,7 +408,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { None, &arg_count_correct, &mut MethodSubstsCtxt { cfcx: self, pick, seg }, - ) + ); + // FIXME(aliemjay): Type annotation should be registered before normalization. + self.normalize_associated_types_in(self.span, substs) } fn unify_receivers( diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 1d021f19104ea..721934a8e5ca7 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1,4 +1,4 @@ -use crate::FnCtxt; +use crate::{FnCtxt, RawTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ @@ -839,7 +839,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &Pat<'tcx>, qpath: &hir::QPath<'_>, - path_resolution: (Res, Option>, &'tcx [hir::PathSegment<'tcx>]), + path_resolution: (Res, Option>, &'tcx [hir::PathSegment<'tcx>]), expected: Ty<'tcx>, ti: TopInfo<'tcx>, ) -> Ty<'tcx> { diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 9eceae8b44f8e..f2e56b1ba1ee7 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -144,6 +144,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { } if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + let self_ty = self.normalize(self_ty); let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs); let impl_self_ty = self.normalize(impl_self_ty); diff --git a/src/test/ui/const-generics/issue-97007.rs b/src/test/ui/const-generics/issue-97007.rs index 7036834c4b119..7b9b9701ff115 100644 --- a/src/test/ui/const-generics/issue-97007.rs +++ b/src/test/ui/const-generics/issue-97007.rs @@ -1,4 +1,8 @@ -// check-pass +//~ ERROR broken MIR + +// known-bug +// failure-status: 101 +// rustc-env: RUSTC_BACKTRACE=0 #![feature(adt_const_params, generic_const_exprs)] #![allow(incomplete_features)] diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs index e321da53d5668..adc0cb4e0423f 100644 --- a/src/test/ui/generic-associated-types/issue-91139.rs +++ b/src/test/ui/generic-associated-types/issue-91139.rs @@ -14,14 +14,6 @@ fn foo() { let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); //~^ ERROR `T` does not live long enough //~| ERROR `T` does not live long enough - //~| ERROR `T` does not live long enough - //~| ERROR `T` does not live long enough - //~| ERROR `T` does not live long enough - //~| ERROR `T` does not live long enough - //~| ERROR `T` does not live long enough - //~| ERROR `T` does not live long enough - //~| ERROR `T` may not live long enough - //~| ERROR `T` may not live long enough // // FIXME: This error is bogus, but it arises because we try to validate // that `<() as Foo>::Type<'a>` is valid, which requires proving diff --git a/src/test/ui/generic-associated-types/issue-91139.stderr b/src/test/ui/generic-associated-types/issue-91139.stderr index 5485570cecd76..d9d76adfbb552 100644 --- a/src/test/ui/generic-associated-types/issue-91139.stderr +++ b/src/test/ui/generic-associated-types/issue-91139.stderr @@ -10,64 +10,5 @@ error: `T` does not live long enough LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `T` does not live long enough - --> $DIR/issue-91139.rs:14:12 - | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `T` does not live long enough - --> $DIR/issue-91139.rs:14:12 - | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/issue-91139.rs:14:58 - | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds - | -help: consider adding an explicit lifetime bound... - | -LL | fn foo() { - | +++++++++ - -error: `T` does not live long enough - --> $DIR/issue-91139.rs:14:58 - | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^^^^ - -error: `T` does not live long enough - --> $DIR/issue-91139.rs:14:58 - | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^^^^ - -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/issue-91139.rs:14:58 - | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds - | -help: consider adding an explicit lifetime bound... - | -LL | fn foo() { - | +++++++++ - -error: `T` does not live long enough - --> $DIR/issue-91139.rs:14:58 - | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^^^^ - -error: `T` does not live long enough - --> $DIR/issue-91139.rs:14:58 - | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^^^^ - -error: aborting due to 10 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs index c10a0888a4f27..8aa29926d4f9b 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs @@ -7,6 +7,7 @@ trait SomeTrait<'a> { fn give_me_ice() { callee:: >::Associated>(); //~^ ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277] + //~| ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277] } fn callee>() { diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr index 25a4f6088deba..3240518fbbe08 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr @@ -1,3 +1,14 @@ +error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied + --> $DIR/issue-85455.rs:8:14 + | +LL | callee:: >::Associated>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | fn give_me_ice SomeTrait<'a>>() { + | +++++++++++++++++++++++ + error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied --> $DIR/issue-85455.rs:8:5 | @@ -9,6 +20,6 @@ help: consider restricting type parameter `T` LL | fn give_me_ice SomeTrait<'a>>() { | +++++++++++++++++++++++ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/nll/closure-malformed-projection-input-issue-102800.rs b/src/test/ui/nll/closure-malformed-projection-input-issue-102800.rs index 25f47f5b6f6c9..260c16c17d4a2 100644 --- a/src/test/ui/nll/closure-malformed-projection-input-issue-102800.rs +++ b/src/test/ui/nll/closure-malformed-projection-input-issue-102800.rs @@ -16,16 +16,6 @@ impl Trait for &'static () { fn main() { let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - //~^ ERROR lifetime may not live long enough - //~| ERROR higher-ranked subtype error - //~| ERROR higher-ranked subtype error - //~| ERROR implementation of `Trait` is not general enough - //~| ERROR implementation of `Trait` is not general enough - //~| ERROR implementation of `Trait` is not general enough - //~| ERROR implementation of `Trait` is not general enough - //~| ERROR implementation of `Trait` is not general enough - //~| ERROR implementation of `Trait` is not general enough - //~| ERROR implementation of `Trait` is not general enough - //~| ERROR implementation of `Trait` is not general enough + //~^ ERROR implementation of `Trait` is not general enough //~| ERROR implementation of `Trait` is not general enough } diff --git a/src/test/ui/nll/closure-malformed-projection-input-issue-102800.stderr b/src/test/ui/nll/closure-malformed-projection-input-issue-102800.stderr index dbd5dabd1dacc..46dba0064339f 100644 --- a/src/test/ui/nll/closure-malformed-projection-input-issue-102800.stderr +++ b/src/test/ui/nll/closure-malformed-projection-input-issue-102800.stderr @@ -1,51 +1,3 @@ -error: lifetime may not live long enough - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^-^ - | || - | |has type `<&'1 () as Trait>::Ty` - | requires that `'1` must outlive `'static` - -error: higher-ranked subtype error - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^ - -error: higher-ranked subtype error - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^ - -error: implementation of `Trait` is not general enough - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^^^^ implementation of `Trait` is not general enough - | - = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`... - = note: ...but `Trait` is actually implemented for the type `&'static ()` - -error: implementation of `Trait` is not general enough - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough - | - = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`... - = note: ...but `Trait` is actually implemented for the type `&'static ()` - -error: implementation of `Trait` is not general enough - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough - | - = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`... - = note: ...but `Trait` is actually implemented for the type `&'static ()` - error: implementation of `Trait` is not general enough --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12 | @@ -64,41 +16,5 @@ LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`... = note: ...but `Trait` is actually implemented for the type `&'static ()` -error: implementation of `Trait` is not general enough - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^^^^ implementation of `Trait` is not general enough - | - = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`... - = note: ...but `Trait` is actually implemented for the type `&'static ()` - -error: implementation of `Trait` is not general enough - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^^^^ implementation of `Trait` is not general enough - | - = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`... - = note: ...but `Trait` is actually implemented for the type `&'static ()` - -error: implementation of `Trait` is not general enough - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^^^^ implementation of `Trait` is not general enough - | - = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`... - = note: ...but `Trait` is actually implemented for the type `&'static ()` - -error: implementation of `Trait` is not general enough - --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48 - | -LL | let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {}; - | ^^^^^^ implementation of `Trait` is not general enough - | - = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`... - = note: ...but `Trait` is actually implemented for the type `&'static ()` - -error: aborting due to 12 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/user-annotations/ascribed-type-wf.rs b/src/test/ui/nll/user-annotations/ascribed-type-wf.rs index 14460dea5b527..5db02c46ec369 100644 --- a/src/test/ui/nll/user-annotations/ascribed-type-wf.rs +++ b/src/test/ui/nll/user-annotations/ascribed-type-wf.rs @@ -1,5 +1,5 @@ -// check-pass -// known-bug: #101350 +// Regression test for #101350. +// check-fail trait Trait { type Ty; @@ -11,6 +11,7 @@ impl Trait for &'static () { fn extend<'a>() { None::<<&'a () as Trait>::Ty>; + //~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/src/test/ui/nll/user-annotations/ascribed-type-wf.stderr b/src/test/ui/nll/user-annotations/ascribed-type-wf.stderr new file mode 100644 index 0000000000000..91e7c6b8ecf1f --- /dev/null +++ b/src/test/ui/nll/user-annotations/ascribed-type-wf.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/ascribed-type-wf.rs:13:5 + | +LL | fn extend<'a>() { + | -- lifetime `'a` defined here +LL | None::<<&'a () as Trait>::Ty>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs index ccda9129dabae..8a80958fc6728 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs @@ -11,8 +11,10 @@ struct SomeStruct { t: T } #[rustc_dump_user_substs] fn main() { SomeStruct { t: 22 }; // Nothing given, no annotation. + //~^ ERROR SomeStruct<^0> SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation. + //~^ ERROR SomeStruct<^0> SomeStruct:: { t: 22 }; // No lifetime bounds given. diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr index 5860621909ce4..b5adc584b288a 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr @@ -1,8 +1,20 @@ -error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None } - --> $DIR/dump-adt-brace-struct.rs:19:5 +error: user substs: UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(0:3 ~ dump_adt_brace_struct[4679]::SomeStruct), self_ty: SomeStruct<^0> }) } + --> $DIR/dump-adt-brace-struct.rs:13:5 + | +LL | SomeStruct { t: 22 }; // Nothing given, no annotation. + | ^^^^^^^^^^^^^^^^^^^^ + +error: user substs: UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(0:3 ~ dump_adt_brace_struct[4679]::SomeStruct), self_ty: SomeStruct<^0> }) } + --> $DIR/dump-adt-brace-struct.rs:16:5 + | +LL | SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation. + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(0:3 ~ dump_adt_brace_struct[4679]::SomeStruct), self_ty: SomeStruct<&ReStatic u32> }) } + --> $DIR/dump-adt-brace-struct.rs:21:5 | LL | SomeStruct::<&'static u32> { t: &22 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/user-annotations/normalization-2.rs b/src/test/ui/nll/user-annotations/normalization-2.rs new file mode 100644 index 0000000000000..00e9eb651cd2d --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-2.rs @@ -0,0 +1,80 @@ +// Make sure we honor region constraints when normalizing type annotations. + +// check-fail + +#![feature(more_qualified_paths)] + +trait Trait { + type Assoc; +} + +impl Trait for T +where + T: 'static, +{ + type Assoc = MyTy<()>; +} + +enum MyTy { + Unit, + Tuple(), + Struct {}, + Dumb(T), +} + +impl MyTy { + fn method() {} +} + +type Ty<'a> = <&'a () as Trait>::Assoc; + +fn test_local<'a>() { + let _: Ty<'a> = MyTy::Unit; + //~^ ERROR lifetime may not live long enough +} + +fn test_closure_sig<'a, 'b>() { + |_: Ty<'a>| {}; + //~^ ERROR lifetime may not live long enough + || -> Option> { None }; + //~^ ERROR lifetime may not live long enough +} + +fn test_path<'a, 'b, 'c, 'd>() { + >::method::>; + //~^ ERROR lifetime may not live long enough + >::method::>; + //~^ ERROR lifetime may not live long enough +} + +fn test_call<'a, 'b, 'c>() { + >::method::>(); + //~^ ERROR lifetime may not live long enough + >::method::>(); + //~^ ERROR lifetime may not live long enough +} + +fn test_variants<'a, 'b, 'c>() { + >::Struct {}; //TODO + //~^ ERROR lifetime may not live long enough + >::Tuple(); + //~^ ERROR lifetime may not live long enough + >::Unit; + //~^ ERROR lifetime may not live long enough +} + +fn test_pattern<'a, 'b, 'c>() { + use MyTy::*; + match MyTy::Unit { + Struct::> {..} => {}, + //~^ ERROR lifetime may not live long enough + Tuple::> (..) => {}, + //~^ ERROR lifetime may not live long enough + Unit::> => {}, + //~^ ERROR lifetime may not live long enough + Dumb(_) => {}, + }; +} + + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/normalization-2.stderr b/src/test/ui/nll/user-annotations/normalization-2.stderr new file mode 100644 index 0000000000000..3c235171ef569 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-2.stderr @@ -0,0 +1,141 @@ +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:32:12 + | +LL | fn test_local<'a>() { + | -- lifetime `'a` defined here +LL | let _: Ty<'a> = MyTy::Unit; + | ^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:37:6 + | +LL | fn test_closure_sig<'a, 'b>() { + | -- lifetime `'a` defined here +LL | |_: Ty<'a>| {}; + | ^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:39:11 + | +LL | fn test_closure_sig<'a, 'b>() { + | -- lifetime `'b` defined here +... +LL | || -> Option> { None }; + | ^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:44:5 + | +LL | fn test_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'a` defined here +LL | >::method::>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:46:5 + | +LL | fn test_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'b` defined here +... +LL | >::method::>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:51:5 + | +LL | fn test_call<'a, 'b, 'c>() { + | -- lifetime `'a` defined here +LL | >::method::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:53:5 + | +LL | fn test_call<'a, 'b, 'c>() { + | -- lifetime `'b` defined here +... +LL | >::method::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:58:5 + | +LL | fn test_variants<'a, 'b, 'c>() { + | -- lifetime `'a` defined here +LL | >::Struct {}; //TODO + | ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:60:5 + | +LL | fn test_variants<'a, 'b, 'c>() { + | -- lifetime `'b` defined here +... +LL | >::Tuple(); + | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:62:5 + | +LL | fn test_variants<'a, 'b, 'c>() { + | -- lifetime `'c` defined here +... +LL | >::Unit; + | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + = help: replace `'c` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:69:9 + | +LL | fn test_pattern<'a, 'b, 'c>() { + | -- lifetime `'a` defined here +... +LL | Struct::> {..} => {}, + | ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:71:9 + | +LL | fn test_pattern<'a, 'b, 'c>() { + | -- lifetime `'b` defined here +... +LL | Tuple::> (..) => {}, + | ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:73:9 + | +LL | fn test_pattern<'a, 'b, 'c>() { + | -- lifetime `'c` defined here +... +LL | Unit::> => {}, + | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + = help: replace `'c` with `'static` + +error: aborting due to 13 previous errors + diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.stderr b/src/test/ui/ufcs/ufcs-partially-resolved.stderr index 3950dc9877cd8..5f7f6aa9f6ec6 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.stderr +++ b/src/test/ui/ufcs/ufcs-partially-resolved.stderr @@ -205,7 +205,7 @@ error[E0223]: ambiguous associated type --> $DIR/ufcs-partially-resolved.rs:36:12 | LL | let _: ::Y::NN; - | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::NN` + | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<::Y as Trait>::NN` error[E0599]: no associated item named `NN` found for type `u16` in the current scope --> $DIR/ufcs-partially-resolved.rs:38:20 From 4327a7902822d2ced5e2115b92610296d231124b Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sat, 29 Oct 2022 16:19:57 +0300 Subject: [PATCH 2/9] introduce AstConv::probe_adt --- .../rustc_hir_analysis/src/astconv/mod.rs | 18 +++++++++------ compiler/rustc_hir_analysis/src/collect.rs | 6 +++++ .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 13 ++++++----- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 23 ++++++++++++------- .../bound-region-variant-resolution.rs | 15 ++++++++++++ .../bound-region-variant-resolution.stderr | 15 ++++++++++++ 6 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/associated-types/bound-region-variant-resolution.rs create mode 100644 src/test/ui/associated-types/bound-region-variant-resolution.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index f65ad2534fc77..32da94da1a60e 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -108,9 +108,12 @@ pub trait AstConv<'tcx> { poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx>; - fn normalize_ty_2(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - ty - } + /// Returns `AdtDef` if `ty` is an ADT. + /// Note that `ty` might be a projection type that needs normalization. + /// This used to get the enum variants in scope of the type. + /// For example, `Self::A` could refer to an associated type + /// or to an enum variant depending on the result of this function. + fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option>; /// Invoked when we encounter an error from some prior pass /// (e.g., resolve) that is translated into a ty-error. This is @@ -1811,7 +1814,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Check if we have an enum variant. let mut variant_resolution = None; - if let ty::Adt(adt_def, _) = self.normalize_ty_2(span, qself_ty).kind() { + if let Some(adt_def) = self.probe_adt(span, qself_ty) { if adt_def.is_enum() { let variant_def = adt_def .variants() @@ -2263,6 +2266,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Option>, kind: DefKind, def_id: DefId, + span: Span, ) -> Vec { // We need to extract the type parameters supplied by the user in // the path `path`. Due to the current setup, this is a bit of a @@ -2330,8 +2334,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Case 2. Reference to a variant constructor. DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => { - let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap()); - let (generics_def_id, index) = if let Some(adt_def) = adt_def { + let (generics_def_id, index) = if let Some(self_ty) = self_ty { + let adt_def = self.probe_adt(span, self_ty).unwrap(); debug_assert!(adt_def.is_enum()); (adt_def.did(), last) } else if last >= 1 && segments[last - 1].args.is_some() { @@ -2428,7 +2432,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert_eq!(opt_self_ty, None); let path_segs = - self.def_ids_for_value_path_segments(path.segments, None, kind, def_id); + self.def_ids_for_value_path_segments(path.segments, None, kind, def_id, span); let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); self.prohibit_generics( diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4641421add958..3e0707a8ba349 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -513,6 +513,12 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } } + fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option> { + // FIXME(aliemjay): We should handle the case where `ty` is a projection, + // but we currently don't. See #103640. + ty.ty_adt_def() + } + fn set_tainted_by_errors(&self, _: ErrorGuaranteed) { // There's no obvious place to track this, so just let it go. } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 97cf5c91d31e8..2c702535467a8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1059,9 +1059,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Res::Def(kind, def_id) => >::def_ids_for_value_path_segments( self, segments, - self_ty.map(|ty| ty.normalized), + self_ty.map(|ty| ty.raw), kind, def_id, + span, ), _ => bug!("instantiate_value_path on {:?}", res), }; @@ -1174,7 +1175,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(false); let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { - let ty = self.normalize_ty_2(span, tcx.at(span).type_of(impl_def_id)); + let ty = tcx.at(span).type_of(impl_def_id); + let ty = self.normalize_associated_types_in(span, ty); match *ty.kind() { ty::Adt(adt_def, substs) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant(); @@ -1297,10 +1299,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we have a default, then we it doesn't matter that we're not // inferring the type arguments: we provide the default where any // is missing. - let default = tcx.bound_type_of(param.def_id); - self.fcx - .normalize_ty_2(self.span, default.subst(tcx, substs.unwrap())) - .into() + let default = + tcx.bound_type_of(param.def_id).subst(tcx, substs.unwrap()); + self.fcx.normalize_associated_types_in(self.span, default).into() } else { // If no type arguments were provided, we have to infer them. // This case also occurs as a result of some malformed input, e.g. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 99dfaef0f8f78..bb270bbae8f49 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -17,7 +17,7 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitable}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; @@ -281,12 +281,15 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.tcx().mk_projection(item_def_id, item_substs) } - fn normalize_ty_2(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - use rustc_middle::ty::TypeVisitable; - if ty.has_escaping_bound_vars() { - ty // FIXME: normalization and escaping regions - } else { - self.normalize_associated_types_in(span, ty) + fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option> { + match ty.kind() { + ty::Adt(adt_def, _) => Some(*adt_def), + // FIXME: We should normalize even with escaping bound vars. + // See test/ui/associated-types/bound-region-variant-resolution.rs + ty::Projection(_) if !ty.has_escaping_bound_vars() => { + self.normalize_associated_types_in(span, ty).ty_adt_def() + } + _ => None, } } @@ -295,7 +298,11 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) { - self.write_ty(hir_id, self.normalize_ty_2(span, ty)) + let ty_normalized = match ty.has_escaping_bound_vars() { + false => self.normalize_associated_types_in(span, ty), + true => ty, // FIXME: normalization and escaping regions + }; + self.write_ty(hir_id, ty_normalized) } } diff --git a/src/test/ui/associated-types/bound-region-variant-resolution.rs b/src/test/ui/associated-types/bound-region-variant-resolution.rs new file mode 100644 index 0000000000000..d3a908ddaff30 --- /dev/null +++ b/src/test/ui/associated-types/bound-region-variant-resolution.rs @@ -0,0 +1,15 @@ +// This is a bug! +// We should emit the same error message regardless of +// whether the projection type contains bound regions. + +// check-fail + +fn test<'x>() { + use std::ops::Deref; + None:: fn(<&'x Option<()> as Deref>::Target::Some)>; + //~^ ERROR expected type, found variant + None:: fn(<&'y Option<()> as Deref>::Target::Some)>; + //~^ ERROR ambiguous associated type +} + +fn main() {} diff --git a/src/test/ui/associated-types/bound-region-variant-resolution.stderr b/src/test/ui/associated-types/bound-region-variant-resolution.stderr new file mode 100644 index 0000000000000..9754fc7b76338 --- /dev/null +++ b/src/test/ui/associated-types/bound-region-variant-resolution.stderr @@ -0,0 +1,15 @@ +error: expected type, found variant `Some` + --> $DIR/bound-region-variant-resolution.rs:9:23 + | +LL | None:: fn(<&'x Option<()> as Deref>::Target::Some)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0223]: ambiguous associated type + --> $DIR/bound-region-variant-resolution.rs:11:23 + | +LL | None:: fn(<&'y Option<()> as Deref>::Target::Some)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<&'y Option<()> as Deref>::Target as Trait>::Some` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0223`. From 32b4b8a68fce0c0f0c50dda91851ea0ce5263f12 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Mon, 31 Oct 2022 11:45:11 +0300 Subject: [PATCH 3/9] fix struct path --- Cargo.lock | 1 + compiler/rustc_hir_typeck/Cargo.toml | 1 + .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 38 ++++++--- src/test/ui/const-generics/issue-97007.rs | 6 +- .../user-annotations/dump-adt-brace-struct.rs | 2 - .../dump-adt-brace-struct.stderr | 18 +--- .../nll/user-annotations/normalization-2.rs | 36 +++++++- .../user-annotations/normalization-2.stderr | 83 +++++++++++++++---- 8 files changed, 137 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95e1787980a17..f0db023a484c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3661,6 +3661,7 @@ dependencies = [ name = "rustc_hir_typeck" version = "0.1.0" dependencies = [ + "either", "rustc_ast", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 093f9bb84486e..114b2d37fb89a 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" +either = "1.5.0" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index b1b4e21e10dfe..4c181016b95bd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -32,6 +32,8 @@ use rustc_span::symbol::Ident; use rustc_span::{self, sym, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; +use either::Either; + use std::iter; use std::mem; use std::ops::ControlFlow; @@ -1215,28 +1217,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return None; } - Res::Def(DefKind::Variant, _) => match ty.normalized.kind() { - ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did(), substs)), + Res::Def(DefKind::Variant, _) => match (ty.raw.kind(), ty.normalized.kind()) { + (ty::Adt(adt, substs), _) => { + Some((adt.variant_of_res(def), adt.did(), substs, Either::Left(substs))) + } + (_, ty::Adt(adt, substs)) => { + Some((adt.variant_of_res(def), adt.did(), substs, Either::Right(ty.raw))) + } _ => bug!("unexpected type: {:?}", ty.normalized), }, Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | Res::SelfTyParam { .. } - | Res::SelfTyAlias { .. } => match ty.normalized.kind() { - ty::Adt(adt, substs) if !adt.is_enum() => { - Some((adt.non_enum_variant(), adt.did(), substs)) + | Res::SelfTyAlias { .. } => match (ty.raw.kind(), ty.normalized.kind()) { + (ty::Adt(adt, substs), _) if !adt.is_enum() => { + Some((adt.non_enum_variant(), adt.did(), substs, Either::Left(substs))) + } + (_, ty::Adt(adt, substs)) if !adt.is_enum() => { + Some((adt.non_enum_variant(), adt.did(), substs, Either::Right(ty.raw))) } _ => None, }, _ => bug!("unexpected definition: {:?}", def), }; - if let Some((variant, did, substs)) = variant { + if let Some((variant, did, substs, user_annotation)) = variant { debug!("check_struct_path: did={:?} substs={:?}", did, substs); - // FIXME(aliemjay): We're using UserSelfTy unconditionally here because it is the only - // way to register the raw user ty, because `substs` is normalized. - let self_ty = ty::UserSelfTy { impl_def_id: did, self_ty: ty.raw }; - self.write_user_type_annotation_from_substs(hir_id, did, substs, Some(self_ty)); + // Register type annotation. + self.probe(|_| { + // UserSubsts and UserSelfTy are mutually exclusive here. + let (user_substs, self_ty) = match user_annotation { + Either::Left(substs) => (*substs, None), + Either::Right(self_ty) => { + (self.fresh_substs_for_item(path_span, did), Some(self_ty)) + } + }; + let self_ty = self_ty.map(|self_ty| ty::UserSelfTy { impl_def_id: did, self_ty }); + self.write_user_type_annotation_from_substs(hir_id, did, user_substs, self_ty); + }); // Check bounds on type arguments used in the path. self.add_required_obligations_for_hir(path_span, did, substs, hir_id); diff --git a/src/test/ui/const-generics/issue-97007.rs b/src/test/ui/const-generics/issue-97007.rs index 7b9b9701ff115..7036834c4b119 100644 --- a/src/test/ui/const-generics/issue-97007.rs +++ b/src/test/ui/const-generics/issue-97007.rs @@ -1,8 +1,4 @@ -//~ ERROR broken MIR - -// known-bug -// failure-status: 101 -// rustc-env: RUSTC_BACKTRACE=0 +// check-pass #![feature(adt_const_params, generic_const_exprs)] #![allow(incomplete_features)] diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs index 8a80958fc6728..ccda9129dabae 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs @@ -11,10 +11,8 @@ struct SomeStruct { t: T } #[rustc_dump_user_substs] fn main() { SomeStruct { t: 22 }; // Nothing given, no annotation. - //~^ ERROR SomeStruct<^0> SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation. - //~^ ERROR SomeStruct<^0> SomeStruct:: { t: 22 }; // No lifetime bounds given. diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr index b5adc584b288a..5860621909ce4 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr @@ -1,20 +1,8 @@ -error: user substs: UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(0:3 ~ dump_adt_brace_struct[4679]::SomeStruct), self_ty: SomeStruct<^0> }) } - --> $DIR/dump-adt-brace-struct.rs:13:5 - | -LL | SomeStruct { t: 22 }; // Nothing given, no annotation. - | ^^^^^^^^^^^^^^^^^^^^ - -error: user substs: UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(0:3 ~ dump_adt_brace_struct[4679]::SomeStruct), self_ty: SomeStruct<^0> }) } - --> $DIR/dump-adt-brace-struct.rs:16:5 - | -LL | SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation. - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(0:3 ~ dump_adt_brace_struct[4679]::SomeStruct), self_ty: SomeStruct<&ReStatic u32> }) } - --> $DIR/dump-adt-brace-struct.rs:21:5 +error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None } + --> $DIR/dump-adt-brace-struct.rs:19:5 | LL | SomeStruct::<&'static u32> { t: &22 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/normalization-2.rs b/src/test/ui/nll/user-annotations/normalization-2.rs index 00e9eb651cd2d..92600155c7f04 100644 --- a/src/test/ui/nll/user-annotations/normalization-2.rs +++ b/src/test/ui/nll/user-annotations/normalization-2.rs @@ -24,6 +24,7 @@ enum MyTy { impl MyTy { fn method() {} + fn method2(&self) {} } type Ty<'a> = <&'a () as Trait>::Assoc; @@ -45,6 +46,9 @@ fn test_path<'a, 'b, 'c, 'd>() { //~^ ERROR lifetime may not live long enough >::method::>; //~^ ERROR lifetime may not live long enough + + MyTy::Unit::>; + //~^ ERROR lifetime may not live long enough } fn test_call<'a, 'b, 'c>() { @@ -55,7 +59,7 @@ fn test_call<'a, 'b, 'c>() { } fn test_variants<'a, 'b, 'c>() { - >::Struct {}; //TODO + >::Struct {}; //~^ ERROR lifetime may not live long enough >::Tuple(); //~^ ERROR lifetime may not live long enough @@ -63,6 +67,36 @@ fn test_variants<'a, 'b, 'c>() { //~^ ERROR lifetime may not live long enough } +fn test_method_call<'a>(x: MyTy<()>) { + // FIXME This should fail. + x.method2::>(); +} + +fn test_struct_path<'a, 'b, 'c, 'd>() { + struct Struct { x: Option, } + + trait Project { + type Struct; + type Enum; + } + impl Project for T { + type Struct = Struct<()>; + type Enum = MyTy<()>; + } + + // Resolves to enum variant + MyTy::>::Struct {}; // without SelfTy + //~^ ERROR lifetime may not live long enough + as Project>::Enum::Struct {}; // with SelfTy + //~^ ERROR lifetime may not live long enough + + // Resolves to struct and associated type respectively + Struct::> { x: None, }; // without SelfTy + //~^ ERROR lifetime may not live long enough + as Project>::Struct { x: None, }; // with SelfTy + //~^ ERROR lifetime may not live long enough +} + fn test_pattern<'a, 'b, 'c>() { use MyTy::*; match MyTy::Unit { diff --git a/src/test/ui/nll/user-annotations/normalization-2.stderr b/src/test/ui/nll/user-annotations/normalization-2.stderr index 3c235171ef569..5dbdb2ecea859 100644 --- a/src/test/ui/nll/user-annotations/normalization-2.stderr +++ b/src/test/ui/nll/user-annotations/normalization-2.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/normalization-2.rs:32:12 + --> $DIR/normalization-2.rs:33:12 | LL | fn test_local<'a>() { | -- lifetime `'a` defined here @@ -7,7 +7,7 @@ LL | let _: Ty<'a> = MyTy::Unit; | ^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:37:6 + --> $DIR/normalization-2.rs:38:6 | LL | fn test_closure_sig<'a, 'b>() { | -- lifetime `'a` defined here @@ -15,7 +15,7 @@ LL | |_: Ty<'a>| {}; | ^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:39:11 + --> $DIR/normalization-2.rs:40:11 | LL | fn test_closure_sig<'a, 'b>() { | -- lifetime `'b` defined here @@ -29,7 +29,7 @@ help: the following changes may resolve your lifetime errors = help: replace `'b` with `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:44:5 + --> $DIR/normalization-2.rs:45:5 | LL | fn test_path<'a, 'b, 'c, 'd>() { | -- lifetime `'a` defined here @@ -37,7 +37,7 @@ LL | >::method::>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:46:5 + --> $DIR/normalization-2.rs:47:5 | LL | fn test_path<'a, 'b, 'c, 'd>() { | -- lifetime `'b` defined here @@ -45,13 +45,23 @@ LL | fn test_path<'a, 'b, 'c, 'd>() { LL | >::method::>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:50:5 + | +LL | fn test_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'c` defined here +... +LL | MyTy::Unit::>; + | ^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + help: the following changes may resolve your lifetime errors | = help: replace `'a` with `'static` = help: replace `'b` with `'static` + = help: replace `'c` with `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:51:5 + --> $DIR/normalization-2.rs:55:5 | LL | fn test_call<'a, 'b, 'c>() { | -- lifetime `'a` defined here @@ -59,7 +69,7 @@ LL | >::method::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:53:5 + --> $DIR/normalization-2.rs:57:5 | LL | fn test_call<'a, 'b, 'c>() { | -- lifetime `'b` defined here @@ -73,15 +83,15 @@ help: the following changes may resolve your lifetime errors = help: replace `'b` with `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:58:5 + --> $DIR/normalization-2.rs:62:5 | LL | fn test_variants<'a, 'b, 'c>() { | -- lifetime `'a` defined here -LL | >::Struct {}; //TODO +LL | >::Struct {}; | ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:60:5 + --> $DIR/normalization-2.rs:64:5 | LL | fn test_variants<'a, 'b, 'c>() { | -- lifetime `'b` defined here @@ -90,7 +100,7 @@ LL | >::Tuple(); | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:62:5 + --> $DIR/normalization-2.rs:66:5 | LL | fn test_variants<'a, 'b, 'c>() { | -- lifetime `'c` defined here @@ -105,7 +115,50 @@ help: the following changes may resolve your lifetime errors = help: replace `'c` with `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:69:9 + --> $DIR/normalization-2.rs:88:5 + | +LL | fn test_struct_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'a` defined here +... +LL | MyTy::>::Struct {}; // without SelfTy + | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:90:5 + | +LL | fn test_struct_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'b` defined here +... +LL | as Project>::Enum::Struct {}; // with SelfTy + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:94:5 + | +LL | fn test_struct_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'c` defined here +... +LL | Struct::> { x: None, }; // without SelfTy + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:96:5 + | +LL | fn test_struct_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'d` defined here +... +LL | as Project>::Struct { x: None, }; // with SelfTy + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + = help: replace `'c` with `'static` + = help: replace `'d` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:103:9 | LL | fn test_pattern<'a, 'b, 'c>() { | -- lifetime `'a` defined here @@ -114,7 +167,7 @@ LL | Struct::> {..} => {}, | ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:71:9 + --> $DIR/normalization-2.rs:105:9 | LL | fn test_pattern<'a, 'b, 'c>() { | -- lifetime `'b` defined here @@ -123,7 +176,7 @@ LL | Tuple::> (..) => {}, | ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:73:9 + --> $DIR/normalization-2.rs:107:9 | LL | fn test_pattern<'a, 'b, 'c>() { | -- lifetime `'c` defined here @@ -137,5 +190,5 @@ help: the following changes may resolve your lifetime errors = help: replace `'b` with `'static` = help: replace `'c` with `'static` -error: aborting due to 13 previous errors +error: aborting due to 18 previous errors From 2ee771f09a66e16a71c0855d18bc96827b313e70 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sat, 29 Oct 2022 20:13:40 +0300 Subject: [PATCH 4/9] fix method substs --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 43 +----------------- .../rustc_hir_typeck/src/method/confirm.rs | 44 ++++++++++++++++++- .../nll/user-annotations/normalization-2.rs | 2 +- .../user-annotations/normalization-2.stderr | 10 ++++- 4 files changed, 53 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2c702535467a8..87651ca9fe47e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -24,7 +24,7 @@ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, Ty, UserType, }; -use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts}; +use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; @@ -162,47 +162,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); self.write_substs(hir_id, method.substs); - - // When the method is confirmed, the `method.substs` includes - // parameters from not just the method, but also the impl of - // the method -- in particular, the `Self` type will be fully - // resolved. However, those are not something that the "user - // specified" -- i.e., those types come from the inferred type - // of the receiver, not something the user wrote. So when we - // create the user-substs, we want to replace those earlier - // types with just the types that the user actually wrote -- - // that is, those that appear on the *method itself*. - // - // As an example, if the user wrote something like - // `foo.bar::(...)` -- the `Self` type here will be the - // type of `foo` (possibly adjusted), but we don't want to - // include that. We want just the `[_, u32]` part. - if !method.substs.is_empty() { - let method_generics = self.tcx.generics_of(method.def_id); - if !method_generics.params.is_empty() { - let user_type_annotation = self.probe(|_| { - let user_substs = UserSubsts { - substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { - let i = param.index as usize; - if i < method_generics.parent_count { - self.var_for_def(DUMMY_SP, param) - } else { - method.substs[i] - } - }), - user_self_ty: None, // not relevant here - }; - - self.canonicalize_user_type_annotation(UserType::TypeOf( - method.def_id, - user_substs, - )) - }); - - debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); - self.write_user_type_annotation(hir_id, user_type_annotation); - } - } } pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 0a20c09666685..aa3001f428a7a 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -12,7 +12,8 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{self, SubstsRef}; use rustc_middle::ty::{self, GenericParamDefKind, Ty}; -use rustc_span::Span; +use rustc_middle::ty::{InternalSubsts, UserSubsts, UserType}; +use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits; use std::iter; @@ -400,6 +401,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.cfcx.var_for_def(self.cfcx.span, param) } } + let substs = >::create_substs_for_generic_args( self.tcx, pick.item.def_id, @@ -409,7 +411,45 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { &arg_count_correct, &mut MethodSubstsCtxt { cfcx: self, pick, seg }, ); - // FIXME(aliemjay): Type annotation should be registered before normalization. + + // When the method is confirmed, the `substs` includes + // parameters from not just the method, but also the impl of + // the method -- in particular, the `Self` type will be fully + // resolved. However, those are not something that the "user + // specified" -- i.e., those types come from the inferred type + // of the receiver, not something the user wrote. So when we + // create the user-substs, we want to replace those earlier + // types with just the types that the user actually wrote -- + // that is, those that appear on the *method itself*. + // + // As an example, if the user wrote something like + // `foo.bar::(...)` -- the `Self` type here will be the + // type of `foo` (possibly adjusted), but we don't want to + // include that. We want just the `[_, u32]` part. + if !substs.is_empty() && !generics.params.is_empty() { + let user_type_annotation = self.probe(|_| { + let user_substs = UserSubsts { + substs: InternalSubsts::for_item(self.tcx, pick.item.def_id, |param, _| { + let i = param.index as usize; + if i < generics.parent_count { + self.fcx.var_for_def(DUMMY_SP, param) + } else { + substs[i] + } + }), + user_self_ty: None, // not relevant here + }; + + self.fcx.canonicalize_user_type_annotation(UserType::TypeOf( + pick.item.def_id, + user_substs, + )) + }); + + debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation); + self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation); + } + self.normalize_associated_types_in(self.span, substs) } diff --git a/src/test/ui/nll/user-annotations/normalization-2.rs b/src/test/ui/nll/user-annotations/normalization-2.rs index 92600155c7f04..232b957d51f98 100644 --- a/src/test/ui/nll/user-annotations/normalization-2.rs +++ b/src/test/ui/nll/user-annotations/normalization-2.rs @@ -68,8 +68,8 @@ fn test_variants<'a, 'b, 'c>() { } fn test_method_call<'a>(x: MyTy<()>) { - // FIXME This should fail. x.method2::>(); + //~^ ERROR lifetime may not live long enough } fn test_struct_path<'a, 'b, 'c, 'd>() { diff --git a/src/test/ui/nll/user-annotations/normalization-2.stderr b/src/test/ui/nll/user-annotations/normalization-2.stderr index 5dbdb2ecea859..50382cfd95376 100644 --- a/src/test/ui/nll/user-annotations/normalization-2.stderr +++ b/src/test/ui/nll/user-annotations/normalization-2.stderr @@ -114,6 +114,14 @@ help: the following changes may resolve your lifetime errors = help: replace `'b` with `'static` = help: replace `'c` with `'static` +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:71:7 + | +LL | fn test_method_call<'a>(x: MyTy<()>) { + | -- lifetime `'a` defined here +LL | x.method2::>(); + | ^^^^^^^ requires that `'a` must outlive `'static` + error: lifetime may not live long enough --> $DIR/normalization-2.rs:88:5 | @@ -190,5 +198,5 @@ help: the following changes may resolve your lifetime errors = help: replace `'b` with `'static` = help: replace `'c` with `'static` -error: aborting due to 18 previous errors +error: aborting due to 19 previous errors From ff6a0aa5807635bbc9ee2200f96c3ce1dbbde368 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 16 Nov 2022 13:11:44 +0300 Subject: [PATCH 5/9] make ascribe_user_type a TypeOp Projection types in user annotations may contain inference variables. This makes the normalization depend on the unification with the actual type and thus requires a separate TypeOp to track the obligations. Otherwise simply calling `TypeChecker::normalize` would ICE with "unexpected ambiguity" --- .../src/type_check/canonical.rs | 78 ++++++++++- .../src/type_check/input_output.rs | 127 +++++++----------- compiler/rustc_borrowck/src/type_check/mod.rs | 76 ++--------- compiler/rustc_middle/src/traits/query.rs | 11 +- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_traits/src/type_op.rs | 35 ++++- .../ui/nll/ty-outlives/wf-unreachable.stderr | 16 +-- .../ui/nll/user-annotations/closure-sig.rs | 15 +++ .../user-annotations/normalization-infer.rs | 40 ++++++ .../normalization-infer.stderr | 101 ++++++++++++++ ...pe-in-supertrait-outlives-container.stderr | 2 +- ...regions-free-region-ordering-caller.stderr | 6 +- ...-outlives-projection-container-hrtb.stderr | 4 +- ...ns-outlives-projection-container-wc.stderr | 2 +- ...gions-outlives-projection-container.stderr | 4 +- 15 files changed, 336 insertions(+), 183 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/closure-sig.rs create mode 100644 src/test/ui/nll/user-annotations/normalization-infer.rs create mode 100644 src/test/ui/nll/user-annotations/normalization-infer.stderr diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index d0cf8622a4470..06434613be7a9 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -1,13 +1,13 @@ use std::fmt; -use rustc_infer::infer::canonical::Canonical; -use rustc_infer::traits::query::NoSolution; +use rustc_infer::infer::{canonical::Canonical, InferOk}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{self, ToPredicate, TypeFoldable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable}; use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; -use rustc_trait_selection::traits::query::Fallible; +use rustc_trait_selection::traits::query::{Fallible, NoSolution}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use crate::diagnostics::{ToUniverseInfo, UniverseInfo}; @@ -179,4 +179,74 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { value }) } + + #[instrument(skip(self), level = "debug")] + pub(super) fn ascribe_user_type( + &mut self, + mir_ty: Ty<'tcx>, + user_ty: ty::UserType<'tcx>, + span: Span, + ) { + // FIXME: Ideally MIR types are normalized, but this is not always true. + let mir_ty = self.normalize(mir_ty, Locations::All(span)); + + self.fully_perform_op( + Locations::All(span), + ConstraintCategory::Boring, + self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)), + ) + .unwrap_or_else(|err| { + span_mirbug!( + self, + span, + "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`", + ); + }); + } + + /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`. + /// + /// FIXME(#104478, #104477): This is a hack for backward-compatibility. + #[instrument(skip(self), level = "debug")] + pub(super) fn ascribe_user_type_skip_wf( + &mut self, + mir_ty: Ty<'tcx>, + user_ty: ty::UserType<'tcx>, + span: Span, + ) { + let ty::UserType::Ty(user_ty) = user_ty else { bug!() }; + + // A fast path for a common case with closure input/output types. + if let ty::Infer(_) = user_ty.kind() { + self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring) + .unwrap(); + return; + } + + let mir_ty = self.normalize(mir_ty, Locations::All(span)); + let cause = ObligationCause::dummy_with_span(span); + let param_env = self.param_env; + let op = |infcx: &'_ _| { + let ocx = ObligationCtxt::new_in_snapshot(infcx); + let user_ty = ocx.normalize(cause.clone(), param_env, user_ty); + ocx.eq(&cause, param_env, user_ty, mir_ty)?; + if !ocx.select_all_or_error().is_empty() { + return Err(NoSolution); + } + Ok(InferOk { value: (), obligations: vec![] }) + }; + + self.fully_perform_op( + Locations::All(span), + ConstraintCategory::Boring, + type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()), + ) + .unwrap_or_else(|err| { + span_mirbug!( + self, + span, + "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`", + ); + }); + } } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 62c6f9581373e..f5721829d1fe3 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -10,7 +10,7 @@ use rustc_index::vec::Idx; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::*; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_span::Span; use crate::universal_regions::UniversalRegions; @@ -18,6 +18,52 @@ use crate::universal_regions::UniversalRegions; use super::{Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + /// Check explicit closure signature annotation, + /// e.g., `|x: FxHashMap<_, &'static u32>| ...`. + #[instrument(skip(self), level = "debug")] + pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { + let mir_def_id = body.source.def_id().expect_local(); + if !self.tcx().is_closure(mir_def_id.to_def_id()) { + return; + } + let Some(user_provided_poly_sig) = + self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id) + else { + return; + }; + + // Instantiate the canonicalized variables from user-provided signature + // (e.g., the `_` in the code above) with fresh variables. + // Then replace the bound items in the fn sig with fresh variables, + // so that they represent the view from "inside" the closure. + let user_provided_sig = self + .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig); + let user_provided_sig = self.infcx.replace_bound_vars_with_fresh_vars( + body.span, + LateBoundRegionConversionTime::FnCall, + user_provided_sig, + ); + + for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip( + // In MIR, closure args begin with an implicit `self`. Skip it! + body.args_iter().skip(1).map(|local| &body.local_decls[local]), + ) { + self.ascribe_user_type_skip_wf( + arg_decl.ty, + ty::UserType::Ty(user_ty), + arg_decl.source_info.span, + ); + } + + // If the user explicitly annotated the output type, enforce it. + let output_decl = &body.local_decls[RETURN_PLACE]; + self.ascribe_user_type_skip_wf( + output_decl.ty, + ty::UserType::Ty(user_provided_sig.output()), + output_decl.source_info.span, + ); + } + #[instrument(skip(self, body, universal_regions), level = "debug")] pub(super) fn equate_inputs_and_outputs( &mut self, @@ -31,40 +77,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!(?normalized_output_ty); debug!(?normalized_input_tys); - let mir_def_id = body.source.def_id().expect_local(); - - // If the user explicitly annotated the input types, extract - // those. - // - // e.g., `|x: FxHashMap<_, &'static u32>| ...` - let user_provided_sig; - if !self.tcx().is_closure(mir_def_id.to_def_id()) { - user_provided_sig = None; - } else { - let typeck_results = self.tcx().typeck(mir_def_id); - user_provided_sig = - typeck_results.user_provided_sigs.get(&mir_def_id).map(|user_provided_poly_sig| { - // Instantiate the canonicalized variables from - // user-provided signature (e.g., the `_` in the code - // above) with fresh variables. - let poly_sig = self.instantiate_canonical_with_fresh_inference_vars( - body.span, - &user_provided_poly_sig, - ); - - // Replace the bound items in the fn sig with fresh - // variables, so that they represent the view from - // "inside" the closure. - self.infcx.replace_bound_vars_with_fresh_vars( - body.span, - LateBoundRegionConversionTime::FnCall, - poly_sig, - ) - }); - } - - debug!(?normalized_input_tys, ?body.local_decls); - // Equate expected input tys with those in the MIR. for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { if argument_index + 1 >= body.local_decls.len() { @@ -87,28 +99,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - if let Some(user_provided_sig) = user_provided_sig { - for (argument_index, &user_provided_input_ty) in - user_provided_sig.inputs().iter().enumerate() - { - // In MIR, closures begin an implicit `self`, so - // argument N is stored in local N+2. - let local = Local::new(argument_index + 2); - let mir_input_ty = body.local_decls[local].ty; - let mir_input_span = body.local_decls[local].source_info.span; - - // If the user explicitly annotated the input types, enforce those. - let user_provided_input_ty = - self.normalize(user_provided_input_ty, Locations::All(mir_input_span)); - - self.equate_normalized_input_or_output( - user_provided_input_ty, - mir_input_ty, - mir_input_span, - ); - } - } - debug!( "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}", body.yield_ty(), @@ -154,29 +144,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { terr ); }; - - // If the user explicitly annotated the output types, enforce those. - // Note that this only happens for closures. - if let Some(user_provided_sig) = user_provided_sig { - let user_provided_output_ty = user_provided_sig.output(); - let user_provided_output_ty = - self.normalize(user_provided_output_ty, Locations::All(output_span)); - if let Err(err) = self.eq_types( - user_provided_output_ty, - mir_output_ty, - Locations::All(output_span), - ConstraintCategory::BoringNoLocation, - ) { - span_mirbug!( - self, - Location::START, - "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", - mir_output_ty, - user_provided_output_ty, - err - ); - } - } } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7467212bed883..71c1d81841d9d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -38,7 +38,6 @@ use rustc_middle::ty::{ use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; -use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -197,6 +196,8 @@ pub(crate) fn type_check<'mir, 'tcx>( } checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); + checker.check_signature_annotation(&body); + liveness::generate( &mut checker, body, @@ -391,23 +392,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { check_err(self, promoted_body, ty, promoted_ty); } } else { - if let Err(terr) = self.cx.fully_perform_op( - locations, - ConstraintCategory::Boring, - self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - constant.literal.ty(), + self.cx.ascribe_user_type( + constant.literal.ty(), + UserType::TypeOf( uv.def.did, UserSubsts { substs: uv.substs, user_self_ty: None }, - )), - ) { - span_mirbug!( - self, - constant, - "bad constant type {:?} ({:?})", - constant, - terr - ); - } + ), + locations.span(&self.cx.body), + ); } } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id); @@ -1041,58 +1033,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!(?self.user_type_annotations); for user_annotation in self.user_type_annotations { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; - let inferred_ty = self.normalize(inferred_ty, Locations::All(span)); let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); - debug!(?annotation); - match annotation { - UserType::Ty(mut ty) => { - ty = self.normalize(ty, Locations::All(span)); - - if let Err(terr) = self.eq_types( - ty, - inferred_ty, - Locations::All(span), - ConstraintCategory::BoringNoLocation, - ) { - span_mirbug!( - self, - user_annotation, - "bad user type ({:?} = {:?}): {:?}", - ty, - inferred_ty, - terr - ); - } - - self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into())), - Locations::All(span), - ConstraintCategory::TypeAnnotation, - ); - } - UserType::TypeOf(def_id, user_substs) => { - if let Err(terr) = self.fully_perform_op( - Locations::All(span), - ConstraintCategory::BoringNoLocation, - self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - inferred_ty, - def_id, - user_substs, - )), - ) { - span_mirbug!( - self, - user_annotation, - "bad user type AscribeUserType({:?}, {:?} {:?}, type_of={:?}): {:?}", - inferred_ty, - def_id, - user_substs, - self.tcx().type_of(def_id), - terr, - ); - } - } - } + self.ascribe_user_type(inferred_ty, annotation, span); } } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index fb152b63f6344..b0dfefecc9302 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -16,22 +16,19 @@ use std::iter::FromIterator; pub mod type_op { use crate::ty::fold::TypeFoldable; - use crate::ty::subst::UserSubsts; - use crate::ty::{Predicate, Ty}; - use rustc_hir::def_id::DefId; + use crate::ty::{Predicate, Ty, UserType}; use std::fmt; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] #[derive(TypeFoldable, TypeVisitable)] pub struct AscribeUserType<'tcx> { pub mir_ty: Ty<'tcx>, - pub def_id: DefId, - pub user_substs: UserSubsts<'tcx>, + pub user_ty: UserType<'tcx>, } impl<'tcx> AscribeUserType<'tcx> { - pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self { - Self { mir_ty, def_id, user_substs } + pub fn new(mir_ty: Ty<'tcx>, user_ty: UserType<'tcx>) -> Self { + Self { mir_ty, user_ty } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8d6ae14231457..e647064bcdbe0 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -918,7 +918,7 @@ impl<'tcx> CanonicalUserType<'tcx> { /// from constants that are named via paths, like `Foo::::new` and /// so forth. #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum UserType<'tcx> { Ty(Ty<'tcx>), diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index f2e56b1ba1ee7..5da6be56bae00 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate}; -use rustc_middle::ty::{UserSelfTy, UserSubsts}; +use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::normalize::AtExt; @@ -52,13 +52,15 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>( key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, span: Option, ) -> Result<(), NoSolution> { - let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts(); - debug!( - "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}", - mir_ty, def_id, user_substs - ); + let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts(); + debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty); let cx = AscribeUserTypeCx { ocx, param_env, span: span.unwrap_or(DUMMY_SP) }; - cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?; + match user_ty { + UserType::Ty(user_ty) => cx.relate_mir_and_user_ty(mir_ty, user_ty)?, + UserType::TypeOf(def_id, user_substs) => { + cx.relate_mir_and_user_substs(mir_ty, def_id, user_substs)? + } + }; Ok(()) } @@ -105,6 +107,25 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { #[instrument(level = "debug", skip(self))] fn relate_mir_and_user_ty( + &self, + mir_ty: Ty<'tcx>, + user_ty: Ty<'tcx>, + ) -> Result<(), NoSolution> { + let user_ty = self.normalize(user_ty); + self.eq(mir_ty, user_ty)?; + + // FIXME(#xxxx): We should check well-formedness before normalization. + self.prove_predicate( + ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())) + .to_predicate(self.tcx()), + ObligationCause::dummy_with_span(self.span), + ); + + Ok(()) + } + + #[instrument(level = "debug", skip(self))] + fn relate_mir_and_user_substs( &self, mir_ty: Ty<'tcx>, def_id: DefId, diff --git a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr index a62157f44f53f..da3bc20832286 100644 --- a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr +++ b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr @@ -5,7 +5,7 @@ LL | fn uninit<'a>() { | -- lifetime `'a` defined here LL | return; LL | let x: &'static &'a (); - | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:11:12 @@ -14,7 +14,7 @@ LL | fn var_type<'a>() { | -- lifetime `'a` defined here LL | return; LL | let x: &'static &'a () = &&(); - | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:15:12 @@ -22,7 +22,7 @@ error: lifetime may not live long enough LL | fn uninit_infer<'a>() { | -- lifetime `'a` defined here LL | let x: &'static &'a _; - | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:21:12 @@ -31,7 +31,7 @@ LL | fn infer<'a>() { | -- lifetime `'a` defined here LL | return; LL | let x: &'static &'a _ = &&(); - | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:26:12 @@ -40,7 +40,7 @@ LL | fn uninit_no_var<'a>() { | -- lifetime `'a` defined here LL | return; LL | let _: &'static &'a (); - | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:31:12 @@ -49,7 +49,7 @@ LL | fn no_var<'a>() { | -- lifetime `'a` defined here LL | return; LL | let _: &'static &'a () = &&(); - | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:36:12 @@ -58,7 +58,7 @@ LL | fn infer_no_var<'a>() { | -- lifetime `'a` defined here LL | return; LL | let _: &'static &'a _ = &&(); - | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:49:12 @@ -67,7 +67,7 @@ LL | fn required_substs<'a>() { | -- lifetime `'a` defined here LL | return; LL | let _: C<'static, 'a, _> = C((), &(), &()); - | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: aborting due to 8 previous errors diff --git a/src/test/ui/nll/user-annotations/closure-sig.rs b/src/test/ui/nll/user-annotations/closure-sig.rs new file mode 100644 index 0000000000000..4dbd3fd8d81e2 --- /dev/null +++ b/src/test/ui/nll/user-annotations/closure-sig.rs @@ -0,0 +1,15 @@ +// This test fails if #104478 is fixed before #104477. + +// check-pass + +struct Printer<'a, 'b>(&'a (), &'b ()); + +impl Printer<'_, '_> { + fn test(self) { + let clo = |_: &'_ Self| {}; + clo(&self); + clo(&self); + } +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/normalization-infer.rs b/src/test/ui/nll/user-annotations/normalization-infer.rs new file mode 100644 index 0000000000000..8bfc272d4ba09 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-infer.rs @@ -0,0 +1,40 @@ +// Annnotations may contain projection types with inference variables as input. +// Make sure we don't get ambiguities when normalizing them. + +// check-fail + +// Single impl. +fn test1(a: A, b: B, c: C) { + trait Tr { type Ty; } + impl Tr for (T,) { type Ty = T; } + + let _: <(_,) as Tr>::Ty = a; //~ ERROR type `A` + Some::<<(_,) as Tr>::Ty>(b); //~ ERROR type `B` + || -> <(_,) as Tr>::Ty { c }; //~ ERROR type `C` + |d: <(_,) as Tr>::Ty| -> D { d }; //~ ERROR type `D` +} + + +// Two impls. The selected impl depends on the actual type. +fn test2(a: A, b: B, c: C) { + trait Tr { type Ty; } + impl Tr for (u8, T) { type Ty = T; } + impl Tr for (i8, T) { type Ty = T; } + type Alias = (<(X, Y) as Tr>::Ty, X); + + fn temp() -> String { todo!() } + + // `u8` impl, requires static. + let _: Alias<_, _> = (a, 0u8); //~ ERROR type `A` + Some::>((b, 0u8)); //~ ERROR type `B` + || -> Alias<_, _> { (c, 0u8) }; //~ ERROR type `C` + + let _: Alias<_, _> = (&temp(), 0u8); //~ ERROR temporary value + Some::>((&temp(), 0u8)); //~ ERROR temporary value + + // `i8` impl, no region constraints. + let _: Alias<_, _> = (&temp(), 0i8); + Some::>((&temp(), 0i8)); +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/normalization-infer.stderr b/src/test/ui/nll/user-annotations/normalization-infer.stderr new file mode 100644 index 0000000000000..12854ab6816b7 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-infer.stderr @@ -0,0 +1,101 @@ +error[E0310]: the parameter type `A` may not live long enough + --> $DIR/normalization-infer.rs:11:12 + | +LL | let _: <(_,) as Tr>::Ty = a; + | ^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn test1(a: A, b: B, c: C) { + | +++++++++ + +error[E0310]: the parameter type `B` may not live long enough + --> $DIR/normalization-infer.rs:12:5 + | +LL | Some::<<(_,) as Tr>::Ty>(b); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn test1(a: A, b: B, c: C) { + | +++++++++ + +error[E0310]: the parameter type `C` may not live long enough + --> $DIR/normalization-infer.rs:13:11 + | +LL | || -> <(_,) as Tr>::Ty { c }; + | ^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn test1(a: A, b: B, c: C) { + | +++++++++ + +error[E0310]: the parameter type `D` may not live long enough + --> $DIR/normalization-infer.rs:14:6 + | +LL | |d: <(_,) as Tr>::Ty| -> D { d }; + | ^ ...so that the type `D` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn test1(a: A, b: B, c: C) { + | +++++++++ + +error[E0310]: the parameter type `A` may not live long enough + --> $DIR/normalization-infer.rs:28:12 + | +LL | let _: Alias<_, _> = (a, 0u8); + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn test2(a: A, b: B, c: C) { + | +++++++++ + +error[E0310]: the parameter type `B` may not live long enough + --> $DIR/normalization-infer.rs:29:5 + | +LL | Some::>((b, 0u8)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn test2(a: A, b: B, c: C) { + | +++++++++ + +error[E0310]: the parameter type `C` may not live long enough + --> $DIR/normalization-infer.rs:30:11 + | +LL | || -> Alias<_, _> { (c, 0u8) }; + | ^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn test2(a: A, b: B, c: C) { + | +++++++++ + +error[E0716]: temporary value dropped while borrowed + --> $DIR/normalization-infer.rs:32:28 + | +LL | let _: Alias<_, _> = (&temp(), 0u8); + | ----------- ^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/normalization-infer.rs:33:27 + | +LL | Some::>((&temp(), 0u8)); + | --^^^^^^------ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | this usage requires that borrow lasts for `'static` + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0310, E0716. +For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr index 87e33e1ccff29..2a26252036181 100644 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr @@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() { | lifetime `'a` defined here ... LL | let _: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.stderr index c79ed50c6a4a6..cdf70d2a5be97 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller.stderr @@ -6,7 +6,7 @@ LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { | | | lifetime `'a` defined here LL | let z: Option<&'b &'a usize> = None; - | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` @@ -19,7 +19,7 @@ LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { | lifetime `'a` defined here LL | let y: Paramd<'a> = Paramd { x: a }; LL | let z: Option<&'b Paramd<'a>> = None; - | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` @@ -31,7 +31,7 @@ LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { | | | lifetime `'a` defined here LL | let z: Option<&'a &'b usize> = None; - | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr index 187e9056e115d..6a7c908fa4009 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr @@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() { | lifetime `'a` defined here ... LL | let _: &'a WithHrAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` @@ -20,7 +20,7 @@ LL | fn with_assoc_sub<'a,'b>() { | lifetime `'a` defined here ... LL | let _: &'a WithHrAssocSub> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr index 4178e951c86ed..eba2a0d585346 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr @@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() { | lifetime `'a` defined here ... LL | let _: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/regions/regions-outlives-projection-container.stderr b/src/test/ui/regions/regions-outlives-projection-container.stderr index 073a31900227e..d20a2f06adfec 100644 --- a/src/test/ui/regions/regions-outlives-projection-container.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container.stderr @@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() { | lifetime `'a` defined here ... LL | let _x: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` @@ -20,7 +20,7 @@ LL | fn without_assoc<'a,'b>() { | lifetime `'a` defined here ... LL | let _x: &'a WithoutAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` From e8cde83d22fb1aac9f48ab8ab238445dde1458f9 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 16 Nov 2022 20:20:26 +0300 Subject: [PATCH 6/9] remove unnecessary normalize call --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 87651ca9fe47e..2b1a0386a5abe 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1258,9 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we have a default, then we it doesn't matter that we're not // inferring the type arguments: we provide the default where any // is missing. - let default = - tcx.bound_type_of(param.def_id).subst(tcx, substs.unwrap()); - self.fcx.normalize_associated_types_in(self.span, default).into() + tcx.bound_type_of(param.def_id).subst(tcx, substs.unwrap()).into() } else { // If no type arguments were provided, we have to infer them. // This case also occurs as a result of some malformed input, e.g. From e6dc8828a0284dfce9ec1ab20f6dac0ea1b827c8 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Tue, 22 Nov 2022 19:40:29 +0300 Subject: [PATCH 7/9] check wf before normalization --- compiler/rustc_traits/src/type_op.rs | 57 ++++++++++++---------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 5da6be56bae00..121f8b4f99d5d 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -101,6 +101,13 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { )); } + fn prove_wf(&self, arg: ty::GenericArg<'tcx>) { + self.prove_predicate( + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()), + ObligationCause::dummy_with_span(self.span), + ); + } + fn tcx(&self) -> TyCtxt<'tcx> { self.ocx.infcx.tcx } @@ -111,16 +118,8 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { mir_ty: Ty<'tcx>, user_ty: Ty<'tcx>, ) -> Result<(), NoSolution> { - let user_ty = self.normalize(user_ty); - self.eq(mir_ty, user_ty)?; - - // FIXME(#xxxx): We should check well-formedness before normalization. - self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())) - .to_predicate(self.tcx()), - ObligationCause::dummy_with_span(self.span), - ); - + self.prove_wf(user_ty.into()); + self.eq(mir_ty, self.normalize(user_ty))?; Ok(()) } @@ -147,8 +146,6 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { // outlives" error messages. let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - let cause = ObligationCause::dummy_with_span(self.span); - debug!(?instantiated_predicates); for (instantiated_predicate, predicate_span) in zip(instantiated_predicates.predicates, instantiated_predicates.spans) @@ -164,35 +161,29 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { self.prove_predicate(instantiated_predicate, cause); } + // Now prove the well-formedness of `def_id` with `substs`. + // Note for some items, proving the WF of `ty` is not sufficient because the + // well-formedness of an item may depend on the WF of gneneric args not present in the + // item's type. Currently this is true for associated consts, e.g.: + // ```rust + // impl MyTy { + // const CONST: () = { /* arbitrary code that depends on T being WF */ }; + // } + // ``` + for arg in substs { + self.prove_wf(arg); + } + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + self.prove_wf(self_ty.into()); + let self_ty = self.normalize(self_ty); let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs); let impl_self_ty = self.normalize(impl_self_ty); self.eq(self_ty, impl_self_ty)?; - - self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())) - .to_predicate(tcx), - cause.clone(), - ); } - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx), - cause, - ); Ok(()) } } From 8e40dde28b6380fdd83a096ed354c2fcd0b568f7 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 23 Nov 2022 00:52:27 +0300 Subject: [PATCH 8/9] tests --- .../nll/user-annotations/associated-consts.rs | 29 +++ .../user-annotations/associated-consts.stderr | 47 +++++ .../nll/user-annotations/normalization-3.rs | 112 +++++++++++ .../user-annotations/normalization-3.stderr | 180 ++++++++++++++++++ 4 files changed, 368 insertions(+) create mode 100644 src/test/ui/nll/user-annotations/associated-consts.rs create mode 100644 src/test/ui/nll/user-annotations/associated-consts.stderr create mode 100644 src/test/ui/nll/user-annotations/normalization-3.rs create mode 100644 src/test/ui/nll/user-annotations/normalization-3.stderr diff --git a/src/test/ui/nll/user-annotations/associated-consts.rs b/src/test/ui/nll/user-annotations/associated-consts.rs new file mode 100644 index 0000000000000..622c62ce934f7 --- /dev/null +++ b/src/test/ui/nll/user-annotations/associated-consts.rs @@ -0,0 +1,29 @@ +struct MyTy(T); +impl MyTy { + const INHERENT: bool = true; +} + +trait Trait { + const TRAIT: bool; +} +impl Trait for MyTy { + const TRAIT: bool = true; +} + +fn test<'a, 'b>() { + MyTy::<&'static &'a ()>::INHERENT; //~ ERROR lifetime + MyTy::<&'static &'b ()>::TRAIT; //~ ERROR lifetime +} + +fn test_normalization<'a, 'b>() { + trait Project { + type Assoc; + } + impl Project for T { + type Assoc = &'static &'static (); + } + MyTy::<<&'a () as Project>::Assoc>::INHERENT; //~ ERROR lifetime + MyTy::<<&'b () as Project>::Assoc>::TRAIT; //~ ERROR lifetime +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/associated-consts.stderr b/src/test/ui/nll/user-annotations/associated-consts.stderr new file mode 100644 index 0000000000000..a5deb82e1a12b --- /dev/null +++ b/src/test/ui/nll/user-annotations/associated-consts.stderr @@ -0,0 +1,47 @@ +error: lifetime may not live long enough + --> $DIR/associated-consts.rs:14:5 + | +LL | fn test<'a, 'b>() { + | -- lifetime `'a` defined here +LL | MyTy::<&'static &'a ()>::INHERENT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/associated-consts.rs:15:5 + | +LL | fn test<'a, 'b>() { + | -- lifetime `'b` defined here +LL | MyTy::<&'static &'a ()>::INHERENT; +LL | MyTy::<&'static &'b ()>::TRAIT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + +error: lifetime may not live long enough + --> $DIR/associated-consts.rs:25:5 + | +LL | fn test_normalization<'a, 'b>() { + | -- lifetime `'a` defined here +... +LL | MyTy::<<&'a () as Project>::Assoc>::INHERENT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/associated-consts.rs:26:5 + | +LL | fn test_normalization<'a, 'b>() { + | -- lifetime `'b` defined here +... +LL | MyTy::<<&'b () as Project>::Assoc>::TRAIT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/nll/user-annotations/normalization-3.rs b/src/test/ui/nll/user-annotations/normalization-3.rs new file mode 100644 index 0000000000000..e67a94cabaf23 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-3.rs @@ -0,0 +1,112 @@ +// Make sure we WF-check user anootations before normalization. +// +// FIXME: add tests for associated trait functions and closure signature. + +// check-fail + +#![feature(more_qualified_paths)] + +trait Trait { + type Assoc; +} + +impl Trait for T { + type Assoc = MyTy<()>; +} + +enum MyTy { + Unit, + Tuple(), + Struct {}, + Dumb(T), +} + +impl MyTy { + fn method() {} + fn method2(&self) {} +} + +type Ty<'a> = <&'static &'a () as Trait>::Assoc; + +fn test_local<'a>() { + let _: Ty<'a> = MyTy::Unit; + //~^ ERROR lifetime may not live long enough +} + +fn test_closure_sig<'a, 'b>() { + // FIXME: these should fail. + |_: Ty<'a>| {}; + || -> Option> { None }; +} + +fn test_path<'a, 'b, 'c, 'd>() { + >::method::>; + //~^ ERROR lifetime may not live long enough + >::method::>; + //~^ ERROR lifetime may not live long enough + + MyTy::Unit::>; + //~^ ERROR lifetime may not live long enough +} + +fn test_call<'a, 'b, 'c>() { + >::method::>(); + //~^ ERROR lifetime may not live long enough + >::method::>(); + //~^ ERROR lifetime may not live long enough +} + +fn test_variants<'a, 'b, 'c>() { + >::Struct {}; + //~^ ERROR lifetime may not live long enough + >::Tuple(); + //~^ ERROR lifetime may not live long enough + >::Unit; + //~^ ERROR lifetime may not live long enough +} + +fn test_method_call<'a>(x: MyTy<()>) { + x.method2::>(); + //~^ ERROR lifetime may not live long enough +} + +fn test_struct_path<'a, 'b, 'c, 'd>() { + struct Struct { x: Option, } + + trait Project { + type Struct; + type Enum; + } + impl Project for T { + type Struct = Struct<()>; + type Enum = MyTy<()>; + } + + // Resolves to enum variant + MyTy::>::Struct {}; // without SelfTy + //~^ ERROR lifetime may not live long enough + as Project>::Enum::Struct {}; // with SelfTy + //~^ ERROR lifetime may not live long enough + + // Resolves to struct and associated type respectively + Struct::> { x: None, }; // without SelfTy + //~^ ERROR lifetime may not live long enough + as Project>::Struct { x: None, }; // with SelfTy + //~^ ERROR lifetime may not live long enough +} + +fn test_pattern<'a, 'b, 'c>() { + use MyTy::*; + match MyTy::Unit { + Struct::> {..} => {}, + //~^ ERROR lifetime may not live long enough + Tuple::> (..) => {}, + //~^ ERROR lifetime may not live long enough + Unit::> => {}, + //~^ ERROR lifetime may not live long enough + Dumb(_) => {}, + }; +} + + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/normalization-3.stderr b/src/test/ui/nll/user-annotations/normalization-3.stderr new file mode 100644 index 0000000000000..135eb436e78fd --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-3.stderr @@ -0,0 +1,180 @@ +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:32:12 + | +LL | fn test_local<'a>() { + | -- lifetime `'a` defined here +LL | let _: Ty<'a> = MyTy::Unit; + | ^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:43:5 + | +LL | fn test_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'a` defined here +LL | >::method::>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:45:5 + | +LL | fn test_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'b` defined here +... +LL | >::method::>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:48:5 + | +LL | fn test_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'c` defined here +... +LL | MyTy::Unit::>; + | ^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + = help: replace `'c` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:53:5 + | +LL | fn test_call<'a, 'b, 'c>() { + | -- lifetime `'a` defined here +LL | >::method::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:55:5 + | +LL | fn test_call<'a, 'b, 'c>() { + | -- lifetime `'b` defined here +... +LL | >::method::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:60:5 + | +LL | fn test_variants<'a, 'b, 'c>() { + | -- lifetime `'a` defined here +LL | >::Struct {}; + | ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:62:5 + | +LL | fn test_variants<'a, 'b, 'c>() { + | -- lifetime `'b` defined here +... +LL | >::Tuple(); + | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:64:5 + | +LL | fn test_variants<'a, 'b, 'c>() { + | -- lifetime `'c` defined here +... +LL | >::Unit; + | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + = help: replace `'c` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:69:7 + | +LL | fn test_method_call<'a>(x: MyTy<()>) { + | -- lifetime `'a` defined here +LL | x.method2::>(); + | ^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:86:5 + | +LL | fn test_struct_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'a` defined here +... +LL | MyTy::>::Struct {}; // without SelfTy + | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:88:5 + | +LL | fn test_struct_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'b` defined here +... +LL | as Project>::Enum::Struct {}; // with SelfTy + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:92:5 + | +LL | fn test_struct_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'c` defined here +... +LL | Struct::> { x: None, }; // without SelfTy + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:94:5 + | +LL | fn test_struct_path<'a, 'b, 'c, 'd>() { + | -- lifetime `'d` defined here +... +LL | as Project>::Struct { x: None, }; // with SelfTy + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + = help: replace `'c` with `'static` + = help: replace `'d` with `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:101:9 + | +LL | fn test_pattern<'a, 'b, 'c>() { + | -- lifetime `'a` defined here +... +LL | Struct::> {..} => {}, + | ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:103:9 + | +LL | fn test_pattern<'a, 'b, 'c>() { + | -- lifetime `'b` defined here +... +LL | Tuple::> (..) => {}, + | ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-3.rs:105:9 + | +LL | fn test_pattern<'a, 'b, 'c>() { + | -- lifetime `'c` defined here +... +LL | Unit::> => {}, + | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + +help: the following changes may resolve your lifetime errors + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + = help: replace `'c` with `'static` + +error: aborting due to 17 previous errors + From 3ba10e216aa07fcf5a30b097affcc776374222d9 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 23 Nov 2022 07:40:04 +0300 Subject: [PATCH 9/9] quick fixes --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 1 - compiler/rustc_traits/src/chalk/lowering.rs | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2b1a0386a5abe..aaf0782fadfce 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1011,7 +1011,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_id: hir::HirId, ) -> (Ty<'tcx>, Res) { let tcx = self.tcx; - assert_eq!(res.ns(), Some(rustc_hir::def::Namespace::ValueNS)); let path_segs = match res { Res::Local(_) | Res::SelfCtor(_) => vec![], diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 06a42a95d6061..716ca9053b347 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -191,7 +191,10 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi GenericArgKind::Const(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } - GenericArgKind::Lifetime(lt) => bug!("unexpected well formed predicate: {:?}", lt), + // Lifetimes are unconditionally well-formed. + GenericArgKind::Lifetime(_) => { + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) + } }, ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal(