Skip to content

Commit 5378f07

Browse files
committed
use deeply_normalize for assumed_wf_types
1 parent d2c7449 commit 5378f07

File tree

10 files changed

+112
-52
lines changed

10 files changed

+112
-52
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4136,6 +4136,7 @@ dependencies = [
41364136
name = "rustc_ty_utils"
41374137
version = "0.0.0"
41384138
dependencies = [
4139+
"itertools",
41394140
"rustc_data_structures",
41404141
"rustc_errors",
41414142
"rustc_fluent_macro",

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
224224
if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
225225
return;
226226
}
227-
check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
227+
228+
let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
228229
}
229230

230231
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
@@ -395,7 +396,7 @@ fn check_opaque_meets_bounds<'tcx>(
395396
def_id: LocalDefId,
396397
span: Span,
397398
origin: &hir::OpaqueTyOrigin,
398-
) {
399+
) -> Result<(), ErrorGuaranteed> {
399400
let defining_use_anchor = match *origin {
400401
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
401402
hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
@@ -429,10 +430,10 @@ fn check_opaque_meets_bounds<'tcx>(
429430
Ok(()) => {}
430431
Err(ty_err) => {
431432
let ty_err = ty_err.to_string(tcx);
432-
tcx.sess.delay_span_bug(
433+
return Err(tcx.sess.delay_span_bug(
433434
span,
434435
format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
435-
);
436+
));
436437
}
437438
}
438439

@@ -447,7 +448,8 @@ fn check_opaque_meets_bounds<'tcx>(
447448
// version.
448449
let errors = ocx.select_all_or_error();
449450
if !errors.is_empty() {
450-
infcx.err_ctxt().report_fulfillment_errors(&errors);
451+
let guar = infcx.err_ctxt().report_fulfillment_errors(&errors);
452+
return Err(guar);
451453
}
452454
match origin {
453455
// Checked when type checking the function containing them.
@@ -461,14 +463,15 @@ fn check_opaque_meets_bounds<'tcx>(
461463
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
462464
// Can have different predicates to their defining use
463465
hir::OpaqueTyOrigin::TyAlias { .. } => {
464-
let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
466+
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
465467
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
466468
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
467-
let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env);
469+
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
468470
}
469471
}
470472
// Clean up after ourselves
471473
let _ = infcx.take_opaque_types();
474+
Ok(())
472475
}
473476

474477
fn is_enum_of_nonnullable_ptr<'tcx>(

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2121,7 +2121,7 @@ pub(super) fn check_type_bounds<'tcx>(
21212121
_ => bug!(),
21222122
}
21232123
};
2124-
let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id);
2124+
let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl_ty_def_id)?;
21252125

21262126
let normalize_cause = ObligationCause::new(
21272127
impl_ty_span,

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,12 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
105105
}
106106
f(&mut wfcx);
107107

108-
let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id);
108+
let assumed_wf_types = match wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)
109+
{
110+
Ok(wf_types) => wf_types,
111+
Err(_guar) => return,
112+
};
113+
109114
let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
110115

111116
let errors = wfcx.select_all_or_error();

compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ use rustc_infer::traits::specialization_graph::Node;
7777
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
7878
use rustc_middle::ty::trait_def::TraitSpecializationKind;
7979
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
80-
use rustc_span::Span;
80+
use rustc_span::{ErrorGuaranteed, Span};
8181
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
8282
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
8383
use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt};
@@ -113,7 +113,7 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
113113
let span = tcx.def_span(impl1_def_id);
114114
check_has_items(tcx, impl1_def_id, impl2_node, span);
115115

116-
if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
116+
if let Ok((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
117117
let impl2_def_id = impl2_node.def_id();
118118
debug!(?impl2_def_id, ?impl2_substs);
119119

@@ -171,16 +171,14 @@ fn get_impl_substs(
171171
tcx: TyCtxt<'_>,
172172
impl1_def_id: LocalDefId,
173173
impl2_node: Node,
174-
) -> Option<(SubstsRef<'_>, SubstsRef<'_>)> {
174+
) -> Result<(SubstsRef<'_>, SubstsRef<'_>), ErrorGuaranteed> {
175175
let infcx = &tcx.infer_ctxt().build();
176176
let ocx = ObligationCtxt::new(infcx);
177177
let param_env = tcx.param_env(impl1_def_id);
178-
179-
let assumed_wf_types =
180-
ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
178+
let impl1_span = tcx.def_span(impl1_def_id);
179+
let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
181180

182181
let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id);
183-
let impl1_span = tcx.def_span(impl1_def_id);
184182
let impl2_substs = translate_substs_with_cause(
185183
infcx,
186184
param_env,
@@ -198,19 +196,19 @@ fn get_impl_substs(
198196

199197
let errors = ocx.select_all_or_error();
200198
if !errors.is_empty() {
201-
ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
202-
return None;
199+
let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
200+
return Err(guar);
203201
}
204202

205203
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
206204
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
207205
let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
208206
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
209207
let span = tcx.def_span(impl1_def_id);
210-
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
211-
return None;
208+
let guar = tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
209+
return Err(guar);
212210
};
213-
Some((impl1_substs, impl2_substs))
211+
Ok((impl1_substs, impl2_substs))
214212
}
215213

216214
/// Returns a list of all of the unconstrained subst of the given impl.

compiler/rustc_middle/src/query/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,7 @@ rustc_queries! {
881881
///
882882
/// Note that we've liberated the late bound regions of function signatures, so
883883
/// this can not be used to check whether these types are well formed.
884-
query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
884+
query assumed_wf_types(key: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
885885
desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
886886
}
887887

compiler/rustc_trait_selection/src/traits/coherence.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,11 @@ fn prove_negated_obligation<'tcx>(
427427
let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID);
428428

429429
let ocx = ObligationCtxt::new(&infcx);
430-
let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
430+
let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id)
431+
else {
432+
return false;
433+
};
434+
431435
let outlives_env = OutlivesEnvironment::with_bounds(
432436
param_env,
433437
infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),

compiler/rustc_trait_selection/src/traits/engine.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::fmt::Debug;
44
use super::TraitEngine;
55
use super::{ChalkFulfillmentContext, FulfillmentContext};
66
use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
7+
use crate::traits::error_reporting::TypeErrCtxtExt;
78
use crate::traits::NormalizeExt;
89
use rustc_data_structures::fx::FxIndexSet;
910
use rustc_errors::ErrorGuaranteed;
@@ -24,7 +25,6 @@ use rustc_middle::ty::ToPredicate;
2425
use rustc_middle::ty::TypeFoldable;
2526
use rustc_middle::ty::{self, Ty, TyCtxt};
2627
use rustc_session::config::TraitSolver;
27-
use rustc_span::Span;
2828

2929
pub trait TraitEngineExt<'tcx> {
3030
fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>;
@@ -198,17 +198,24 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
198198
}
199199
}
200200

201+
pub fn assumed_wf_types_and_report_errors(
202+
&self,
203+
param_env: ty::ParamEnv<'tcx>,
204+
def_id: LocalDefId,
205+
) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> {
206+
self.assumed_wf_types(param_env, def_id)
207+
.map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(&errors))
208+
}
209+
201210
pub fn assumed_wf_types(
202211
&self,
203212
param_env: ty::ParamEnv<'tcx>,
204-
span: Span,
205213
def_id: LocalDefId,
206-
) -> FxIndexSet<Ty<'tcx>> {
214+
) -> Result<FxIndexSet<Ty<'tcx>>, Vec<FulfillmentError<'tcx>>> {
207215
let tcx = self.infcx.tcx;
208-
let assumed_wf_types = tcx.assumed_wf_types(def_id);
209216
let mut implied_bounds = FxIndexSet::default();
210-
let cause = ObligationCause::misc(span, def_id);
211-
for ty in assumed_wf_types {
217+
let mut errors = Vec::new();
218+
for &(ty, span) in tcx.assumed_wf_types(def_id) {
212219
// FIXME(@lcnr): rustc currently does not check wf for types
213220
// pre-normalization, meaning that implied bounds are sometimes
214221
// incorrect. See #100910 for more details.
@@ -221,10 +228,15 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
221228
// sound and then uncomment this line again.
222229

223230
// implied_bounds.insert(ty);
224-
let normalized = self.normalize(&cause, param_env, ty);
225-
implied_bounds.insert(normalized);
231+
let cause = ObligationCause::misc(span, def_id);
232+
match self.infcx.at(&cause, param_env).deeply_normalize(ty) {
233+
// Insert well-formed types, ignoring duplicates.
234+
Ok(normalized) => drop(implied_bounds.insert(normalized)),
235+
Err(normalization_errors) => errors.extend(normalization_errors),
236+
};
226237
}
227-
implied_bounds
238+
239+
if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) }
228240
}
229241

230242
pub fn make_canonicalized_query_response<T>(

compiler/rustc_ty_utils/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2021"
55

66
[dependencies]
77
tracing = "0.1"
8+
itertools = "0.10.1"
89
rustc_middle = { path = "../rustc_middle" }
910
rustc_data_structures = { path = "../rustc_data_structures" }
1011
rustc_errors = { path = "../rustc_errors" }

compiler/rustc_ty_utils/src/implied_bounds.rs

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,56 @@
1-
use rustc_hir::{def::DefKind, def_id::DefId};
1+
use rustc_hir as hir;
2+
use rustc_hir::def::DefKind;
3+
use rustc_hir::def_id::LocalDefId;
24
use rustc_middle::query::Providers;
35
use rustc_middle::ty::{self, Ty, TyCtxt};
6+
use rustc_span::Span;
7+
use std::iter;
48

59
pub fn provide(providers: &mut Providers) {
610
*providers = Providers { assumed_wf_types, ..*providers };
711
}
812

9-
fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
13+
fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
1014
match tcx.def_kind(def_id) {
1115
DefKind::Fn => {
1216
let sig = tcx.fn_sig(def_id).subst_identity();
13-
let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
14-
liberated_sig.inputs_and_output
17+
let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
18+
tcx.arena.alloc_from_iter(itertools::zip_eq(
19+
liberated_sig.inputs_and_output,
20+
fn_sig_spans(tcx, def_id),
21+
))
1522
}
1623
DefKind::AssocFn => {
1724
let sig = tcx.fn_sig(def_id).subst_identity();
18-
let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
25+
let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
1926
let mut assumed_wf_types: Vec<_> =
20-
tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into();
21-
assumed_wf_types.extend(liberated_sig.inputs_and_output);
22-
tcx.mk_type_list(&assumed_wf_types)
27+
tcx.assumed_wf_types(tcx.local_parent(def_id)).into();
28+
assumed_wf_types.extend(itertools::zip_eq(
29+
liberated_sig.inputs_and_output,
30+
fn_sig_spans(tcx, def_id),
31+
));
32+
tcx.arena.alloc_slice(&assumed_wf_types)
2333
}
2434
DefKind::Impl { .. } => {
25-
match tcx.impl_trait_ref(def_id) {
26-
Some(trait_ref) => {
27-
let types: Vec<_> = trait_ref.skip_binder().substs.types().collect();
28-
tcx.mk_type_list(&types)
29-
}
30-
// Only the impl self type
31-
None => tcx.mk_type_list(&[tcx.type_of(def_id).subst_identity()]),
32-
}
35+
// Trait arguments and the self type for trait impls or only the self type for
36+
// inherent impls.
37+
let tys = match tcx.impl_trait_ref(def_id) {
38+
Some(trait_ref) => trait_ref.skip_binder().substs.types().collect(),
39+
None => vec![tcx.type_of(def_id).subst_identity()],
40+
};
41+
42+
let mut impl_spans = impl_spans(tcx, def_id);
43+
tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
3344
}
34-
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
35-
DefKind::OpaqueTy => match tcx.def_kind(tcx.parent(def_id)) {
45+
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
46+
DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
3647
DefKind::TyAlias => ty::List::empty(),
37-
DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
48+
DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
3849
// Nested opaque types only occur in associated types:
3950
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
4051
// assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself
4152
// and `&'static T`.
42-
DefKind::OpaqueTy => bug!("unimplemented implied bounds for neseted opaque types"),
53+
DefKind::OpaqueTy => bug!("unimplemented implied bounds for nested opaque types"),
4354
def_kind @ _ => {
4455
bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}")
4556
}
@@ -72,3 +83,28 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
7283
| DefKind::Generator => ty::List::empty(),
7384
}
7485
}
86+
87+
fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ {
88+
let node = tcx.hir().get(tcx.local_def_id_to_hir_id(def_id));
89+
if let Some(decl) = node.fn_decl() {
90+
decl.inputs.iter().map(|ty| ty.span).chain(iter::once(decl.output.span()))
91+
} else {
92+
bug!("unexpected item for fn {def_id:?}: {node:?}")
93+
}
94+
}
95+
96+
fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ {
97+
let item = tcx.hir().expect_item(def_id);
98+
if let hir::ItemKind::Impl(impl_) = item.kind {
99+
let trait_args = impl_
100+
.of_trait
101+
.into_iter()
102+
.flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args)
103+
.map(|arg| arg.span());
104+
let dummy_spans_for_default_args =
105+
impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span));
106+
iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args)
107+
} else {
108+
bug!("unexpected item for impl {def_id:?}: {item:?}")
109+
}
110+
}

0 commit comments

Comments
 (0)