From d227506683e846cbeb872e089d660187a7a6041f 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 | 37 ++--- compiler/rustc_hir_analysis/src/collect.rs | 5 - compiler/rustc_hir_typeck/src/closure.rs | 6 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 67 +++++---- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 32 ++-- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 21 ++- .../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, 376 insertions(+), 257 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 1b334f65b9ecc..bcb695cc8e3c2 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -106,11 +106,9 @@ pub trait AstConv<'tcx> { poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx>; - /// Normalize an associated type coming from the user. - /// - /// This should only be used by astconv. Use `FnCtxt::normalize` - /// or `ObligationCtxt::normalize` in downstream crates. - 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 @@ -485,14 +483,7 @@ 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, - tcx.at(self.span) - .bound_type_of(param.def_id) - .subst(tcx, substs), - ) - .into() + tcx.at(self.span).bound_type_of(param.def_id).subst(tcx, substs).into() } else if infer_args { self.astconv.ty_infer(Some(param), self.span).into() } else { @@ -1254,7 +1245,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, self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs)) + self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs) } fn conv_object_ty_poly_trait_ref( @@ -1786,7 +1777,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. @@ -1814,7 +1805,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, adt_substs) = qself_ty.kind() { + if let ty::Adt(adt_def, adt_substs) = self.normalize_ty_2(span, qself_ty).kind() { if adt_def.is_enum() { let variant_def = adt_def .variants() @@ -1923,7 +1914,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { adt_substs, ); let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs); - let ty = self.normalize_ty(span, ty); return Ok((ty, DefKind::AssocTy, assoc_ty_did)); } } @@ -2020,7 +2010,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( @@ -2156,7 +2145,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>( @@ -2417,7 +2406,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 @@ -2577,7 +2566,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) => { @@ -2720,8 +2709,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 { @@ -2731,8 +2719,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 7afde550b42ad..fd54aec480ab6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -505,11 +505,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 3453da500b984..399702fd41abc 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -647,14 +647,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(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(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 634688de01a65..3e05f67b74bc8 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}; @@ -410,23 +410,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(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> { @@ -780,7 +784,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 @@ -803,7 +807,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`") @@ -811,7 +816,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)); @@ -819,7 +824,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)), @@ -830,13 +835,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, @@ -849,7 +858,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. @@ -986,7 +995,7 @@ 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, @@ -996,7 +1005,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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), }; @@ -1007,8 +1020,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) => { @@ -1027,7 +1040,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 }); } } @@ -1109,7 +1122,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(); @@ -1193,7 +1206,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() @@ -1227,7 +1240,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. @@ -1250,13 +1263,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, @@ -1269,7 +1282,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); // 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(span, substs_raw); self.add_required_obligations_for_hir(span, def_id, &substs, hir_id); @@ -1287,6 +1303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // with the substituted impl type. // This also occurs for an enum variant on a type alias. let impl_ty = self.normalize(span, tcx.bound_type_of(impl_def_id).subst(tcx, substs)); + let self_ty = self.normalize(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 7d6b4aaebf4ea..6a822568775bd 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; @@ -1231,13 +1231,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)) } @@ -1248,14 +1248,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 @@ -1268,7 +1272,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(); @@ -1656,20 +1660,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. @@ -1678,7 +1683,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 30b59da7852d4..d7e53a0aa0477 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -17,8 +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::visit::TypeVisitable; -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}; @@ -298,7 +297,7 @@ 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> { if ty.has_escaping_bound_vars() { ty // FIXME: normalization and escaping regions } else { @@ -310,7 +309,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 99e09b86a2323..69929589541f5 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -297,7 +297,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(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 218c54688aa3e..f2a41720b605d 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -372,7 +372,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() @@ -397,7 +397,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, @@ -405,7 +405,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(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 e0304fa2d3b98..1075378a15955 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::{ @@ -842,7 +842,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 7f964afde80fd..f6eca97743035 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -91,6 +91,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>( } if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + let self_ty = ocx.normalize(&cause, param_env, self_ty); let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs); let impl_self_ty = ocx.normalize(&cause, param_env, 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 34329d6f6c73a6f0080e169007d099a40db3aea1 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 | 22 +++++++++++++------ compiler/rustc_hir_analysis/src/collect.rs | 5 +++++ .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 13 ++++++----- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 17 +++++++++----- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index bcb695cc8e3c2..df6600626a30b 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -106,9 +106,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 @@ -1805,7 +1808,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, adt_substs) = 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() @@ -1907,6 +1910,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else { continue; }; + let ty::Adt(_, adt_substs) = qself_ty.kind() else { + // FIXME(inherent_associated_types) + bug!("unimplemented: non-adt self of inherent assoc ty"); + }; let item_substs = self.create_substs_for_associated_item( span, assoc_ty_did, @@ -2262,6 +2269,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 @@ -2329,8 +2337,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() { @@ -2426,7 +2434,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 fd54aec480ab6..b7f259668a1e4 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -505,6 +505,11 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } } + fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option> { + // FIXME(#103640): Should we handle the case where `ty` is a projection? + 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 3e05f67b74bc8..6c2dfaf4413be 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1007,9 +1007,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), }; @@ -1122,7 +1123,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(span, ty); match *ty.kind() { ty::Adt(adt_def, substs) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant(); @@ -1238,10 +1240,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(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 d7e53a0aa0477..6347b9a69a007 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -297,11 +297,14 @@ 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> { - if ty.has_escaping_bound_vars() { - ty // FIXME: normalization and escaping regions - } else { - self.normalize(span, ty) + fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option> { + match ty.kind() { + ty::Adt(adt_def, _) => Some(*adt_def), + // FIXME(#104767): Should we handle bound regions here? + ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => { + self.normalize(span, ty).ty_adt_def() + } + _ => None, } } @@ -310,7 +313,9 @@ 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)) + // FIXME: normalization and escaping regions + let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty }; + self.write_ty(hir_id, ty) } } From be5a45d39240ab3f6410c4808b0840142c657228 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 4f48506b5af4f..fd55c121bc4ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4134,6 +4134,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 6a822568775bd..92a0b9785d042 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::{kw, 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; @@ -1231,28 +1233,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 37b40e471a62425cb34781bad763b5cb5047f13c 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 6c2dfaf4413be..e9e43950fb2b6 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, 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; @@ -161,47 +161,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 f2a41720b605d..a2c6e246610b2 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; @@ -397,6 +398,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, @@ -406,7 +408,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(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 c6a17bf8bcfa60c8b0436251d2cf70d8eca4d198 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 | 126 +++++++----------- compiler/rustc_borrowck/src/type_check/mod.rs | 76 ++--------- compiler/rustc_middle/src/traits/query.rs | 11 +- .../rustc_middle/src/ty/typeck_results.rs | 2 +- compiler/rustc_traits/src/type_op.rs | 53 ++++++-- .../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, 350 insertions(+), 186 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 3617bf58be9dd..02222c0a03cb3 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}; @@ -177,4 +177,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, 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 8fa43f8528cca..fa9ea769a14f7 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, body), 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,39 +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()) { - None - } else { - let typeck_results = self.tcx().typeck(mir_def_id); - - 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() { @@ -86,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(), @@ -153,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 247607ff29e20..8778a19eeda1b 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 6a149be3137ee..543f5b87e00bc 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -15,22 +15,19 @@ use rustc_span::source_map::Span; 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/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 136a4906c58de..bc7895c39707a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -679,7 +679,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 f6eca97743035..aa5c83ac2e655 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -4,8 +4,8 @@ use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; 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::{ParamEnvAnd, Predicate}; +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::QueryNormalizeExt; @@ -50,13 +50,46 @@ 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 span = span.unwrap_or(DUMMY_SP); + match user_ty { + UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, + UserType::TypeOf(def_id, user_substs) => { + relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)? + } + }; + Ok(()) +} + +#[instrument(level = "debug", skip(ocx, param_env, span))] +fn relate_mir_and_user_ty<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + mir_ty: Ty<'tcx>, + user_ty: Ty<'tcx>, +) -> Result<(), NoSolution> { + let cause = ObligationCause::dummy_with_span(span); + let user_ty = ocx.normalize(&cause, param_env, user_ty); + ocx.eq(&cause, param_env, mir_ty, user_ty)?; + // FIXME(#104764): We should check well-formedness before normalization. + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())); + ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); + + Ok(()) +} + +#[instrument(level = "debug", skip(ocx, param_env, span))] +fn relate_mir_and_user_substs<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + mir_ty: Ty<'tcx>, + def_id: hir::def_id::DefId, + user_substs: UserSubsts<'tcx>, +) -> Result<(), NoSolution> { let UserSubsts { user_self_ty, substs } = user_substs; let tcx = ocx.infcx.tcx; let cause = ObligationCause::dummy_with_span(span); @@ -97,8 +130,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>( ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let predicate: Predicate<'tcx> = - ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())).to_predicate(tcx); + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())); ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); } @@ -113,8 +145,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>( // them? This would only be relevant if some input // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... - let predicate: Predicate<'tcx> = - ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx); + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())); ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); Ok(()) } 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 8afd3c47a800f0ebd40d1dc91d498ca02b3ab484 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 e9e43950fb2b6..f5cffef54e0ee 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1199,9 +1199,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(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 dca15fd5b95c01edd81ccee1c0f0bdbc28d3f05f Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 23 Nov 2022 11:30:58 +0300 Subject: [PATCH 7/9] rename create_raw_ty -> handle_raw_ty --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 6 +++--- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index f5cffef54e0ee..970e84bf054e3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -369,14 +369,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub fn create_raw_ty(&self, span: Span, ty: Ty<'tcx>) -> RawTy<'tcx> { + pub fn handle_raw_ty(&self, span: Span, ty: Ty<'tcx>) -> RawTy<'tcx> { RawTy { raw: ty, normalized: self.normalize(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)); - self.create_raw_ty(ast_t.span, t) + self.handle_raw_ty(ast_t.span, t) } pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { @@ -767,7 +767,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We manually call `register_wf_obligation` in the success path // below. let ty = >::ast_ty_to_ty_in_path(self, qself); - (self.create_raw_ty(span, ty), qself, segment) + (self.handle_raw_ty(span, ty), qself, segment) } QPath::LangItem(..) => { bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`") diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 92a0b9785d042..229220888957b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1683,7 +1683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { QPath::Resolved(ref maybe_qself, ref path) => { 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, self.create_raw_ty(path_span, ty)) + (path.res, self.handle_raw_ty(path_span, ty)) } QPath::TypeRelative(ref qself, ref segment) => { let ty = self.to_ty(qself); @@ -1692,7 +1692,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 ty = self.handle_raw_ty(path_span, ty); let result = result.map(|(_, kind, def_id)| (kind, def_id)); // Write back the new resolution. @@ -1702,7 +1702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } QPath::LangItem(lang_item, span, id) => { let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id); - (res, self.create_raw_ty(path_span, ty)) + (res, self.handle_raw_ty(path_span, ty)) } } } From 030d60f1c729c01ef9ea11a1adb153c7c58e5fe2 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sun, 25 Dec 2022 12:27:14 +0300 Subject: [PATCH 8/9] more tests --- .../nll/user-annotations/normalization-2.rs | 46 +++++- .../user-annotations/normalization-2.stderr | 152 ++++++++++++++---- .../ui/nll/user-annotations/normalization.rs | 9 +- .../nll/user-annotations/normalization.stderr | 18 ++- .../associated-type-impl-trait-lifetime.rs | 20 +++ 5 files changed, 208 insertions(+), 37 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs diff --git a/src/test/ui/nll/user-annotations/normalization-2.rs b/src/test/ui/nll/user-annotations/normalization-2.rs index 232b957d51f98..be23c3b747858 100644 --- a/src/test/ui/nll/user-annotations/normalization-2.rs +++ b/src/test/ui/nll/user-annotations/normalization-2.rs @@ -23,10 +23,20 @@ enum MyTy { } impl MyTy { + const CONST: () = (); fn method() {} fn method2(&self) {} } +trait TraitAssoc { + const TRAIT_CONST: (); + fn trait_method(&self); +} +impl TraitAssoc for T { + const TRAIT_CONST: () = (); + fn trait_method(&self) {} +} + type Ty<'a> = <&'a () as Trait>::Assoc; fn test_local<'a>() { @@ -41,13 +51,30 @@ fn test_closure_sig<'a, 'b>() { //~^ ERROR lifetime may not live long enough } -fn test_path<'a, 'b, 'c, 'd>() { +fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { >::method::>; //~^ ERROR lifetime may not live long enough >::method::>; //~^ ERROR lifetime may not live long enough - MyTy::Unit::>; + >::trait_method::>; + //~^ ERROR lifetime may not live long enough + >::trait_method::>; + //~^ ERROR lifetime may not live long enough + + >::CONST; + //~^ ERROR lifetime may not live long enough + >::TRAIT_CONST; + //~^ ERROR lifetime may not live long enough + + >::method::>; + >::trait_method::>; + >::CONST; + >::TRAIT_CONST; + + MyTy::Unit::>; + //~^ ERROR lifetime may not live long enough + MyTy::>::Unit; //~^ ERROR lifetime may not live long enough } @@ -67,9 +94,11 @@ fn test_variants<'a, 'b, 'c>() { //~^ ERROR lifetime may not live long enough } -fn test_method_call<'a>(x: MyTy<()>) { +fn test_method_call<'a, 'b>(x: MyTy<()>) { x.method2::>(); //~^ ERROR lifetime may not live long enough + x.trait_method::>(); + //~^ ERROR lifetime may not live long enough } fn test_struct_path<'a, 'b, 'c, 'd>() { @@ -97,7 +126,7 @@ fn test_struct_path<'a, 'b, 'c, 'd>() { //~^ ERROR lifetime may not live long enough } -fn test_pattern<'a, 'b, 'c>() { +fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() { use MyTy::*; match MyTy::Unit { Struct::> {..} => {}, @@ -108,6 +137,15 @@ fn test_pattern<'a, 'b, 'c>() { //~^ ERROR lifetime may not live long enough Dumb(_) => {}, }; + 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(_) => {}, + }; } diff --git a/src/test/ui/nll/user-annotations/normalization-2.stderr b/src/test/ui/nll/user-annotations/normalization-2.stderr index 50382cfd95376..5299282ea151e 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:33:12 + --> $DIR/normalization-2.rs:43: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:38:6 + --> $DIR/normalization-2.rs:48: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:40:11 + --> $DIR/normalization-2.rs:50:11 | LL | fn test_closure_sig<'a, 'b>() { | -- lifetime `'b` defined here @@ -29,39 +29,89 @@ 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:45:5 + --> $DIR/normalization-2.rs:55:5 | -LL | fn test_path<'a, 'b, 'c, 'd>() { +LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { | -- lifetime `'a` defined here LL | >::method::>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:47:5 + --> $DIR/normalization-2.rs:57:5 | -LL | fn test_path<'a, 'b, 'c, 'd>() { +LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { | -- lifetime `'b` defined here ... LL | >::method::>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:50:5 + --> $DIR/normalization-2.rs:60:5 | -LL | fn test_path<'a, 'b, 'c, 'd>() { +LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { | -- lifetime `'c` defined here ... -LL | MyTy::Unit::>; - | ^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` +LL | >::trait_method::>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:62:5 + | +LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { + | -- lifetime `'d` defined here +... +LL | >::trait_method::>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:65:5 + | +LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { + | -- lifetime `'e` defined here +... +LL | >::CONST; + | ^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:67:5 + | +LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { + | -- lifetime `'f` defined here +... +LL | >::TRAIT_CONST; + | ^^^^^^^^^^^^^^^^^^^^^ requires that `'f` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:75:5 + | +LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { + | -- lifetime `'g` defined here +... +LL | MyTy::Unit::>; + | ^^^^^^^^^^^^^^^^^^^^ requires that `'g` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:77:5 + | +LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() { + | -- lifetime `'h` defined here +... +LL | MyTy::>::Unit; + | ^^^^^^^^^^^^^^^^^^^^ requires that `'h` 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` + = help: replace `'e` with `'static` + = help: replace `'f` with `'static` + = help: replace `'g` with `'static` + = help: replace `'h` with `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:55:5 + --> $DIR/normalization-2.rs:82:5 | LL | fn test_call<'a, 'b, 'c>() { | -- lifetime `'a` defined here @@ -69,7 +119,7 @@ LL | >::method::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:57:5 + --> $DIR/normalization-2.rs:84:5 | LL | fn test_call<'a, 'b, 'c>() { | -- lifetime `'b` defined here @@ -83,7 +133,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:62:5 + --> $DIR/normalization-2.rs:89:5 | LL | fn test_variants<'a, 'b, 'c>() { | -- lifetime `'a` defined here @@ -91,7 +141,7 @@ LL | >::Struct {}; | ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:64:5 + --> $DIR/normalization-2.rs:91:5 | LL | fn test_variants<'a, 'b, 'c>() { | -- lifetime `'b` defined here @@ -100,7 +150,7 @@ LL | >::Tuple(); | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:66:5 + --> $DIR/normalization-2.rs:93:5 | LL | fn test_variants<'a, 'b, 'c>() { | -- lifetime `'c` defined here @@ -115,15 +165,29 @@ 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:71:7 + --> $DIR/normalization-2.rs:98:7 | -LL | fn test_method_call<'a>(x: MyTy<()>) { +LL | fn test_method_call<'a, 'b>(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 + --> $DIR/normalization-2.rs:100:7 + | +LL | fn test_method_call<'a, 'b>(x: MyTy<()>) { + | -- lifetime `'b` defined here +... +LL | x.trait_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:117:5 | LL | fn test_struct_path<'a, 'b, 'c, 'd>() { | -- lifetime `'a` defined here @@ -132,7 +196,7 @@ LL | MyTy::>::Struct {}; // without SelfTy | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:90:5 + --> $DIR/normalization-2.rs:119:5 | LL | fn test_struct_path<'a, 'b, 'c, 'd>() { | -- lifetime `'b` defined here @@ -141,7 +205,7 @@ 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 + --> $DIR/normalization-2.rs:123:5 | LL | fn test_struct_path<'a, 'b, 'c, 'd>() { | -- lifetime `'c` defined here @@ -150,7 +214,7 @@ 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 + --> $DIR/normalization-2.rs:125:5 | LL | fn test_struct_path<'a, 'b, 'c, 'd>() { | -- lifetime `'d` defined here @@ -166,37 +230,67 @@ help: the following changes may resolve your lifetime errors = help: replace `'d` with `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:103:9 + --> $DIR/normalization-2.rs:132:9 | -LL | fn test_pattern<'a, 'b, 'c>() { +LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() { | -- lifetime `'a` defined here ... LL | Struct::> {..} => {}, | ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:105:9 + --> $DIR/normalization-2.rs:134:9 | -LL | fn test_pattern<'a, 'b, 'c>() { +LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() { | -- lifetime `'b` defined here ... LL | Tuple::> (..) => {}, | ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` error: lifetime may not live long enough - --> $DIR/normalization-2.rs:107:9 + --> $DIR/normalization-2.rs:136:9 | -LL | fn test_pattern<'a, 'b, 'c>() { +LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() { | -- lifetime `'c` defined here ... LL | Unit::> => {}, | ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static` +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:141:9 + | +LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() { + | -- lifetime `'d` defined here +... +LL | >::Struct {..} => {}, + | ^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:143:9 + | +LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() { + | -- lifetime `'e` defined here +... +LL | >::Tuple (..) => {}, + | ^^^^^^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:145:9 + | +LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() { + | -- lifetime `'f` defined here +... +LL | >::Unit => {}, + | ^^^^^^^^^^^^^^ requires that `'f` 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` + = help: replace `'e` with `'static` + = help: replace `'f` with `'static` -error: aborting due to 19 previous errors +error: aborting due to 28 previous errors diff --git a/src/test/ui/nll/user-annotations/normalization.rs b/src/test/ui/nll/user-annotations/normalization.rs index 870e3d8110cd5..c2e892f573c2d 100644 --- a/src/test/ui/nll/user-annotations/normalization.rs +++ b/src/test/ui/nll/user-annotations/normalization.rs @@ -3,8 +3,15 @@ trait Foo { type Out; } impl Foo for () { type Out = &'static u32; } +impl<'a> Foo for &'a () { type Out = &'a u32; } fn main() { let a = 22; - let b: <() as Foo>::Out = &a; //~ ERROR + let _: <() as Foo>::Out = &a; //~ ERROR + + let a = 22; + let _: <&'static () as Foo>::Out = &a; //~ ERROR + + let a = 22; + let _: <&'_ () as Foo>::Out = &a; } diff --git a/src/test/ui/nll/user-annotations/normalization.stderr b/src/test/ui/nll/user-annotations/normalization.stderr index 4c7893789a535..975cb4b66d91d 100644 --- a/src/test/ui/nll/user-annotations/normalization.stderr +++ b/src/test/ui/nll/user-annotations/normalization.stderr @@ -1,13 +1,25 @@ error[E0597]: `a` does not live long enough - --> $DIR/normalization.rs:9:31 + --> $DIR/normalization.rs:10:31 | -LL | let b: <() as Foo>::Out = &a; +LL | let _: <() as Foo>::Out = &a; | ---------------- ^^ borrowed value does not live long enough | | | type annotation requires that `a` is borrowed for `'static` +... LL | } | - `a` dropped here while still borrowed -error: aborting due to previous error +error[E0597]: `a` does not live long enough + --> $DIR/normalization.rs:13:40 + | +LL | let _: <&'static () as Foo>::Out = &a; + | ------------------------- ^^ borrowed value does not live long enough + | | + | type annotation requires that `a` is borrowed for `'static` +... +LL | } + | - `a` dropped here while still borrowed + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs b/src/test/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs new file mode 100644 index 0000000000000..962606508be7a --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs @@ -0,0 +1,20 @@ +//check-pass + +#![feature(type_alias_impl_trait)] + +trait Trait { + type Opaque1; + type Opaque2; + fn constrain(self); +} + +impl<'a> Trait for &'a () { + type Opaque1 = impl Sized; + type Opaque2 = impl Sized + 'a; + fn constrain(self) { + let _: Self::Opaque1 = (); + let _: Self::Opaque2 = self; + } +} + +fn main() {} From bf228ace5cf6824078d6d36144ad8a65f07fa8d3 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Mon, 26 Dec 2022 01:03:24 +0300 Subject: [PATCH 9/9] don't eagerly normalize SelfCtor type Delay until user annotations are registered. See the added test. --- Cargo.lock | 1 - compiler/rustc_hir_typeck/Cargo.toml | 1 - .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 28 ++++++++++----- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 34 +++++------------- .../user-annotations/normalization-default.rs | 22 ++++++++++++ .../normalization-default.stderr | 36 +++++++++++++++++++ .../user-annotations/normalization-self.rs | 26 ++++++++++++++ .../normalization-self.stderr | 36 +++++++++++++++++++ 8 files changed, 148 insertions(+), 36 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/normalization-default.rs create mode 100644 src/test/ui/nll/user-annotations/normalization-default.stderr create mode 100644 src/test/ui/nll/user-annotations/normalization-self.rs create mode 100644 src/test/ui/nll/user-annotations/normalization-self.stderr diff --git a/Cargo.lock b/Cargo.lock index fd55c121bc4ed..4f48506b5af4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4134,7 +4134,6 @@ 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 114b2d37fb89a..093f9bb84486e 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -8,7 +8,6 @@ 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/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 970e84bf054e3..b7681d108ed01 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -392,6 +392,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty.normalized } + pub(super) fn user_substs_for_adt(ty: RawTy<'tcx>) -> UserSubsts<'tcx> { + match (ty.raw.kind(), ty.normalized.kind()) { + (ty::Adt(_, substs), _) => UserSubsts { substs, user_self_ty: None }, + (_, ty::Adt(adt, substs)) => UserSubsts { + substs, + user_self_ty: Some(UserSelfTy { impl_def_id: adt.did(), self_ty: ty.raw }), + }, + _ => bug!("non-adt type {:?}", ty), + } + } + pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> { match length { &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span), @@ -1082,20 +1093,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(false); let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { - let ty = tcx.at(span).type_of(impl_def_id); - let ty = self.normalize(span, ty); - match *ty.kind() { - ty::Adt(adt_def, substs) if adt_def.has_ctor() => { - let variant = adt_def.non_enum_variant(); - let (ctor_kind, ctor_def_id) = variant.ctor.unwrap(); - (Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id), Some(substs)) + let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id)); + match ty.normalized.ty_adt_def() { + Some(adt_def) if adt_def.has_ctor() => { + let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); + let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); + let user_substs = Self::user_substs_for_adt(ty); + user_self_ty = user_substs.user_self_ty; + (new_res, Some(user_substs.substs)) } _ => { let mut err = tcx.sess.struct_span_err( span, "the `Self` constructor can only be used with tuple or unit structs", ); - if let Some(adt_def) = ty.ty_adt_def() { + if let Some(adt_def) = ty.normalized.ty_adt_def() { match adt_def.adt_kind() { AdtKind::Enum => { err.help("did you mean to use one of the enum's variants?"); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 229220888957b..da411d0642e72 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -32,8 +32,6 @@ use rustc_span::symbol::{kw, 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; @@ -1233,44 +1231,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return None; } - 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))) + Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() { + Some(adt) => { + Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty))) } _ => bug!("unexpected type: {:?}", ty.normalized), }, Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | Res::SelfTyParam { .. } - | 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))) + | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() { + Some(adt) if !adt.is_enum() => { + Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty))) } _ => None, }, _ => bug!("unexpected definition: {:?}", def), }; - if let Some((variant, did, substs, user_annotation)) = variant { + if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant { debug!("check_struct_path: did={:?} substs={:?}", did, substs); // 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); - }); + self.write_user_type_annotation_from_substs(hir_id, did, substs, user_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/nll/user-annotations/normalization-default.rs b/src/test/ui/nll/user-annotations/normalization-default.rs new file mode 100644 index 0000000000000..fa52e6d857f6f --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-default.rs @@ -0,0 +1,22 @@ +// check-fail + +trait Trait { type Assoc; } +impl<'a> Trait for &'a () { type Assoc = &'a (); } + +struct MyTuple::Assoc>(T, U); +fn test_tuple(x: &(), y: &()) { + MyTuple::<_>((), x); + //~^ ERROR + let _: MyTuple::<_> = MyTuple((), y); + //~^ ERROR +} + +struct MyStruct::Assoc> { val: (T, U), } +fn test_struct(x: &(), y: &()) { + MyStruct::<_> { val: ((), x) }; + //~^ ERROR + let _: MyStruct::<_> = MyStruct { val: ((), y) }; + //~^ ERROR +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/normalization-default.stderr b/src/test/ui/nll/user-annotations/normalization-default.stderr new file mode 100644 index 0000000000000..6c73ac6925481 --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-default.stderr @@ -0,0 +1,36 @@ +error: lifetime may not live long enough + --> $DIR/normalization-default.rs:8:22 + | +LL | fn test_tuple(x: &(), y: &()) { + | - let's call the lifetime of this reference `'1` +LL | MyTuple::<_>((), x); + | ^ this usage requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-default.rs:10:12 + | +LL | fn test_tuple(x: &(), y: &()) { + | - let's call the lifetime of this reference `'2` +... +LL | let _: MyTuple::<_> = MyTuple((), y); + | ^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-default.rs:16:26 + | +LL | fn test_struct(x: &(), y: &()) { + | - let's call the lifetime of this reference `'1` +LL | MyStruct::<_> { val: ((), x) }; + | ^^^^^^^ this usage requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-default.rs:18:12 + | +LL | fn test_struct(x: &(), y: &()) { + | - let's call the lifetime of this reference `'2` +... +LL | let _: MyStruct::<_> = MyStruct { val: ((), y) }; + | ^^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/nll/user-annotations/normalization-self.rs b/src/test/ui/nll/user-annotations/normalization-self.rs new file mode 100644 index 0000000000000..c18760b53cffb --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-self.rs @@ -0,0 +1,26 @@ +// check-fail + +trait Trait { type Assoc; } +impl<'a> Trait for &'a () { type Assoc = &'a (); } + +struct MyTuple(T); +impl MyTuple<<&'static () as Trait>::Assoc> { + fn test(x: &(), y: &()) { + Self(x); + //~^ ERROR + let _: Self = MyTuple(y); + //~^ ERROR + } +} + +struct MyStruct { val: T, } +impl MyStruct<<&'static () as Trait>::Assoc> { + fn test(x: &(), y: &()) { + Self { val: x }; + //~^ ERROR + let _: Self = MyStruct { val: y }; + //~^ ERROR + } +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/normalization-self.stderr b/src/test/ui/nll/user-annotations/normalization-self.stderr new file mode 100644 index 0000000000000..e231ed03c2eea --- /dev/null +++ b/src/test/ui/nll/user-annotations/normalization-self.stderr @@ -0,0 +1,36 @@ +error: lifetime may not live long enough + --> $DIR/normalization-self.rs:9:14 + | +LL | fn test(x: &(), y: &()) { + | - let's call the lifetime of this reference `'1` +LL | Self(x); + | ^ this usage requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-self.rs:11:16 + | +LL | fn test(x: &(), y: &()) { + | - let's call the lifetime of this reference `'2` +... +LL | let _: Self = MyTuple(y); + | ^^^^ type annotation requires that `'2` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-self.rs:19:21 + | +LL | fn test(x: &(), y: &()) { + | - let's call the lifetime of this reference `'1` +LL | Self { val: x }; + | ^ this usage requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/normalization-self.rs:21:16 + | +LL | fn test(x: &(), y: &()) { + | - let's call the lifetime of this reference `'2` +... +LL | let _: Self = MyStruct { val: y }; + | ^^^^ type annotation requires that `'2` must outlive `'static` + +error: aborting due to 4 previous errors +