diff options
| author | Michael Goulet <michael@errs.io> | 2023-01-08 02:40:59 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2023-01-08 18:50:08 +0000 |
| commit | ca554efaf78962f9dc9599663b29626269c69c8c (patch) | |
| tree | 3958b41c6b13ed4740a484744b29b24a9b05d358 /compiler | |
| parent | fa51fc01ca3d654d08d627b1d1482d1b77e5ed8b (diff) | |
| download | rust-ca554efaf78962f9dc9599663b29626269c69c8c.tar.gz rust-ca554efaf78962f9dc9599663b29626269c69c8c.zip | |
Improve spans of non-WF implied bound types
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 58 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/engine.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/implied_bounds.rs | 67 |
4 files changed, 82 insertions, 51 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 1afe6242403..b663f90cab7 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1489,54 +1489,38 @@ fn check_fn_or_method<'tcx>( def_id: LocalDefId, ) { let tcx = wfcx.tcx(); - let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); + let mut sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` // on the entire `FnSig`, since this would use the same `WellFormedLoc` // for each type, preventing the HIR wf check from generating // a nice error message. - let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig; - inputs_and_output = tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| { - wfcx.normalize( - span, - Some(WellFormedLoc::Param { - function: def_id, - // Note that the `param_idx` of the output type is - // one greater than the index of the last input type. - param_idx: i.try_into().unwrap(), - }), - ty, - ) - })); - // Manually call `normalize_associated_types_in` on the other types - // in `FnSig`. This ensures that if the types of these fields - // ever change to include projections, we will start normalizing - // them automatically. - let sig = ty::FnSig { - inputs_and_output, - c_variadic: wfcx.normalize(span, None, c_variadic), - unsafety: wfcx.normalize(span, None, unsafety), - abi: wfcx.normalize(span, None, abi), - }; + let arg_span = + |idx| hir_decl.inputs.get(idx).map_or(hir_decl.output.span(), |arg: &hir::Ty<'_>| arg.span); + + sig.inputs_and_output = + tcx.mk_type_list(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| { + wfcx.normalize( + arg_span(idx), + Some(WellFormedLoc::Param { + function: def_id, + // Note that the `param_idx` of the output type is + // one greater than the index of the last input type. + param_idx: idx.try_into().unwrap(), + }), + ty, + ) + })); - for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() { + for (idx, ty) in sig.inputs_and_output.iter().enumerate() { wfcx.register_wf_obligation( - ty.span, - Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }), - input_ty.into(), + arg_span(idx), + Some(WellFormedLoc::Param { function: def_id, param_idx: idx.try_into().unwrap() }), + ty.into(), ); } - wfcx.register_wf_obligation( - hir_decl.output.span(), - Some(WellFormedLoc::Param { - function: def_id, - param_idx: sig.inputs().len().try_into().unwrap(), - }), - sig.output().into(), - ); - check_where_clauses(wfcx, span, def_id); check_return_position_impl_trait_in_trait_bounds( diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 37db2274f67..7f794a926c0 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -803,7 +803,7 @@ rustc_queries! { /// /// Note that we've liberated the late bound regions of function signatures, so /// this can not be used to check whether these types are well formed. - query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> { + query assumed_wf_types(key: DefId) -> &'tcx [(Ty<'tcx>, Span)] { desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index bc6d9d4b922..72ed3aa499d 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -191,8 +191,8 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { let assumed_wf_types = tcx.assumed_wf_types(def_id); let mut implied_bounds = FxIndexSet::default(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let cause = ObligationCause::misc(span, hir_id); - for ty in assumed_wf_types { + for &(ty, ty_span) in assumed_wf_types { + let span = if ty_span.is_dummy() { span } else { ty_span }; // FIXME(@lcnr): rustc currently does not check wf for types // pre-normalization, meaning that implied bounds are sometimes // incorrect. See #100910 for more details. @@ -205,7 +205,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { // sound and then uncomment this line again. // implied_bounds.insert(ty); - let normalized = self.normalize(&cause, param_env, ty); + let normalized = self.normalize(&ObligationCause::misc(span, hir_id), param_env, ty); implied_bounds.insert(normalized); } implied_bounds diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index b7a24a22c53..e3f34373ccc 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -1,33 +1,80 @@ use crate::rustc_middle::ty::DefIdTree; -use rustc_hir::{def::DefKind, def_id::DefId}; +use rustc_hir::{self as hir, def::DefKind, def_id::DefId}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{Span, DUMMY_SP}; pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { assumed_wf_types, ..*providers }; } -fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { +fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &[(Ty<'_>, Span)] { match tcx.def_kind(def_id) { DefKind::Fn => { let sig = tcx.fn_sig(def_id); let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig); - liberated_sig.inputs_and_output + if let Some(node) = tcx.hir().get_if_local(def_id) + && let Some(decl) = node.fn_decl() + { + assert_eq!(decl.inputs.len(), liberated_sig.inputs().len()); + tcx.arena.alloc_from_iter(std::iter::zip( + liberated_sig.inputs_and_output, + decl.inputs.iter().map(|ty| ty.span).chain([decl.output.span()]), + )) + } else { + tcx.arena.alloc_from_iter( + liberated_sig.inputs_and_output.iter().map(|ty| (ty, DUMMY_SP)), + ) + } } DefKind::AssocFn => { let sig = tcx.fn_sig(def_id); let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig); - let mut assumed_wf_types: Vec<_> = - tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into(); - assumed_wf_types.extend(liberated_sig.inputs_and_output); - tcx.intern_type_list(&assumed_wf_types) + let assumed_wf_types = tcx.assumed_wf_types(tcx.parent(def_id)); + if let Some(node) = tcx.hir().get_if_local(def_id) + && let Some(decl) = node.fn_decl() + { + assert_eq!(decl.inputs.len(), liberated_sig.inputs().len()); + tcx.arena.alloc_from_iter(assumed_wf_types.iter().copied().chain(std::iter::zip( + liberated_sig.inputs_and_output, + decl.inputs.iter().map(|ty| ty.span).chain([decl.output.span()]), + ))) + } else { + tcx.arena.alloc_from_iter(assumed_wf_types.iter().copied().chain( + liberated_sig.inputs_and_output.iter().map(|ty| (ty, DUMMY_SP)), + )) + } } DefKind::Impl => match tcx.impl_trait_ref(def_id) { Some(trait_ref) => { let types: Vec<_> = trait_ref.substs.types().collect(); - tcx.intern_type_list(&types) + let self_span = if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(impl_), + .. + })) = tcx.hir().get_if_local(def_id) + { + impl_.self_ty.span + } else { + DUMMY_SP + }; + tcx.arena.alloc_from_iter(std::iter::zip( + types, + // FIXME: reliable way of getting trait ref substs... + [self_span].into_iter().chain(std::iter::repeat(DUMMY_SP)), + )) } // Only the impl self type - None => tcx.intern_type_list(&[tcx.type_of(def_id)]), + None => { + let span = if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(impl_), + .. + })) = tcx.hir().get_if_local(def_id) + { + impl_.self_ty.span + } else { + DUMMY_SP + }; + tcx.arena.alloc_from_iter([(tcx.type_of(def_id), span)]) + } }, DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)), DefKind::Mod @@ -56,6 +103,6 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Closure - | DefKind::Generator => ty::List::empty(), + | DefKind::Generator => &[], } } |
