Skip to content

Commit 9d28fe3

Browse files
committed
Auto merge of rust-lang#139000 - compiler-errors:rigid-missing-item, r=lcnr
Rigidly project missing item due to guaranteed impossible sized predicate This is a somewhat involved change, but it amounts to treating missing impl items due to guaranteed impossible where clauses (dyn/str/slice sized, cc rust-lang#135480) as *rigid projections* rather than projecting to an error term, since that was preventing either reporting a proper error (in an empty param env) *or* successfully type checking the code (in the presence of trivially false where clauses). Fixes rust-lang#138970 r? `@lcnr` `@oli-obk`
2 parents 6813f95 + 6cd724b commit 9d28fe3

19 files changed

+524
-91
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+3-27
Original file line numberDiff line numberDiff line change
@@ -937,31 +937,7 @@ fn check_impl_items_against_trait<'tcx>(
937937

938938
let trait_def = tcx.trait_def(trait_ref.def_id);
939939

940-
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
941-
942-
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
943-
let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
944-
let param_env = tcx.param_env(impl_id);
945-
946-
let self_is_guaranteed_unsized = match tcx
947-
.struct_tail_raw(
948-
trait_ref.self_ty(),
949-
|ty| {
950-
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
951-
Ty::new_error_with_message(
952-
tcx,
953-
tcx.def_span(impl_id),
954-
"struct tail should be computable",
955-
)
956-
})
957-
},
958-
|| (),
959-
)
960-
.kind()
961-
{
962-
ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
963-
_ => false,
964-
};
940+
let self_is_guaranteed_unsize_self = tcx.impl_self_is_guaranteed_unsized(impl_id);
965941

966942
for &impl_item in impl_item_refs {
967943
let ty_impl_item = tcx.associated_item(impl_item);
@@ -992,7 +968,7 @@ fn check_impl_items_against_trait<'tcx>(
992968
}
993969
}
994970

995-
if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
971+
if self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(ty_trait_item.def_id) {
996972
tcx.emit_node_span_lint(
997973
rustc_lint_defs::builtin::DEAD_CODE,
998974
tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
@@ -1027,7 +1003,7 @@ fn check_impl_items_against_trait<'tcx>(
10271003
if !is_implemented
10281004
&& tcx.defaultness(impl_id).is_final()
10291005
// unsized types don't need to implement methods that have `Self: Sized` bounds.
1030-
&& !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id))
1006+
&& !(self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(trait_item_id))
10311007
{
10321008
missing_items.push(tcx.associated_item(trait_item_id));
10331009
}

compiler/rustc_middle/src/query/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,13 @@ rustc_queries! {
10261026
separate_provide_extern
10271027
}
10281028

1029+
/// Given an `impl_def_id`, return true if the self type is guaranteed to be unsized due
1030+
/// to either being one of the built-in unsized types (str/slice/dyn) or to be a struct
1031+
/// whose tail is one of those types.
1032+
query impl_self_is_guaranteed_unsized(impl_def_id: DefId) -> bool {
1033+
desc { |tcx| "computing whether `{}` has a guaranteed unsized self type", tcx.def_path_str(impl_def_id) }
1034+
}
1035+
10291036
/// Maps a `DefId` of a type to a list of its inherent impls.
10301037
/// Contains implementations of methods that are inherent to a type.
10311038
/// Methods in these implementations don't need to be exported.

compiler/rustc_middle/src/ty/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
437437
)
438438
}
439439

440+
fn impl_self_is_guaranteed_unsized(self, impl_def_id: DefId) -> bool {
441+
self.impl_self_is_guaranteed_unsized(impl_def_id)
442+
}
443+
440444
fn has_target_features(self, def_id: DefId) -> bool {
441445
!self.codegen_fn_attrs(def_id).target_features.is_empty()
442446
}

compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs

+29-3
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ where
134134
// Add GAT where clauses from the trait's definition
135135
// FIXME: We don't need these, since these are the type's own WF obligations.
136136
ecx.add_goals(
137-
GoalSource::Misc,
137+
GoalSource::AliasWellFormed,
138138
cx.own_predicates_of(goal.predicate.def_id())
139139
.iter_instantiated(cx, goal.predicate.alias.args)
140140
.map(|pred| goal.with(cx, pred)),
@@ -199,7 +199,7 @@ where
199199
// Add GAT where clauses from the trait's definition.
200200
// FIXME: We don't need these, since these are the type's own WF obligations.
201201
ecx.add_goals(
202-
GoalSource::Misc,
202+
GoalSource::AliasWellFormed,
203203
cx.own_predicates_of(goal.predicate.def_id())
204204
.iter_instantiated(cx, goal.predicate.alias.args)
205205
.map(|pred| goal.with(cx, pred)),
@@ -232,7 +232,33 @@ where
232232
};
233233

234234
if !cx.has_item_definition(target_item_def_id) {
235-
return error_response(ecx, cx.delay_bug("missing item"));
235+
// If the impl is missing an item, it's either because the user forgot to
236+
// provide it, or the user is not *obligated* to provide it (because it
237+
// has a trivially false `Sized` predicate). If it's the latter, we cannot
238+
// delay a bug because we can have trivially false where clauses, so we
239+
// treat it as rigid.
240+
if cx.impl_self_is_guaranteed_unsized(impl_def_id) {
241+
match ecx.typing_mode() {
242+
ty::TypingMode::Coherence => {
243+
return ecx.evaluate_added_goals_and_make_canonical_response(
244+
Certainty::AMBIGUOUS,
245+
);
246+
}
247+
ty::TypingMode::Analysis { .. }
248+
| ty::TypingMode::Borrowck { .. }
249+
| ty::TypingMode::PostBorrowckAnalysis { .. }
250+
| ty::TypingMode::PostAnalysis => {
251+
ecx.structurally_instantiate_normalizes_to_term(
252+
goal,
253+
goal.predicate.alias,
254+
);
255+
return ecx
256+
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
257+
}
258+
}
259+
} else {
260+
return error_response(ecx, cx.delay_bug("missing item"));
261+
}
236262
}
237263

238264
let target_container_def_id = cx.parent(target_item_def_id);

compiler/rustc_trait_selection/src/traits/project.rs

+45-45
Original file line numberDiff line numberDiff line change
@@ -669,30 +669,11 @@ fn project<'cx, 'tcx>(
669669

670670
match candidates {
671671
ProjectionCandidateSet::Single(candidate) => {
672-
Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)))
672+
confirm_candidate(selcx, obligation, candidate)
673673
}
674674
ProjectionCandidateSet::None => {
675675
let tcx = selcx.tcx();
676-
let term = match tcx.def_kind(obligation.predicate.def_id) {
677-
DefKind::AssocTy => Ty::new_projection_from_args(
678-
tcx,
679-
obligation.predicate.def_id,
680-
obligation.predicate.args,
681-
)
682-
.into(),
683-
DefKind::AssocConst => ty::Const::new_unevaluated(
684-
tcx,
685-
ty::UnevaluatedConst::new(
686-
obligation.predicate.def_id,
687-
obligation.predicate.args,
688-
),
689-
)
690-
.into(),
691-
kind => {
692-
bug!("unknown projection def-id: {}", kind.descr(obligation.predicate.def_id))
693-
}
694-
};
695-
676+
let term = obligation.predicate.to_term(tcx);
696677
Ok(Projected::NoProgress(term))
697678
}
698679
// Error occurred while trying to processing impls.
@@ -1244,18 +1225,16 @@ fn confirm_candidate<'cx, 'tcx>(
12441225
selcx: &mut SelectionContext<'cx, 'tcx>,
12451226
obligation: &ProjectionTermObligation<'tcx>,
12461227
candidate: ProjectionCandidate<'tcx>,
1247-
) -> Progress<'tcx> {
1228+
) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
12481229
debug!(?obligation, ?candidate, "confirm_candidate");
1249-
let mut progress = match candidate {
1230+
let mut result = match candidate {
12501231
ProjectionCandidate::ParamEnv(poly_projection)
1251-
| ProjectionCandidate::Object(poly_projection) => {
1252-
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
1253-
}
1254-
1255-
ProjectionCandidate::TraitDef(poly_projection) => {
1256-
confirm_param_env_candidate(selcx, obligation, poly_projection, true)
1257-
}
1258-
1232+
| ProjectionCandidate::Object(poly_projection) => Ok(Projected::Progress(
1233+
confirm_param_env_candidate(selcx, obligation, poly_projection, false),
1234+
)),
1235+
ProjectionCandidate::TraitDef(poly_projection) => Ok(Projected::Progress(
1236+
confirm_param_env_candidate(selcx, obligation, poly_projection, true),
1237+
)),
12591238
ProjectionCandidate::Select(impl_source) => {
12601239
confirm_select_candidate(selcx, obligation, impl_source)
12611240
}
@@ -1266,23 +1245,26 @@ fn confirm_candidate<'cx, 'tcx>(
12661245
// with new region variables, we need to resolve them to existing variables
12671246
// when possible for this to work. See `auto-trait-projection-recursion.rs`
12681247
// for a case where this matters.
1269-
if progress.term.has_infer_regions() {
1248+
if let Ok(Projected::Progress(progress)) = &mut result
1249+
&& progress.term.has_infer_regions()
1250+
{
12701251
progress.term = progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx));
12711252
}
1272-
progress
1253+
1254+
result
12731255
}
12741256

12751257
fn confirm_select_candidate<'cx, 'tcx>(
12761258
selcx: &mut SelectionContext<'cx, 'tcx>,
12771259
obligation: &ProjectionTermObligation<'tcx>,
12781260
impl_source: Selection<'tcx>,
1279-
) -> Progress<'tcx> {
1261+
) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
12801262
match impl_source {
12811263
ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
12821264
ImplSource::Builtin(BuiltinImplSource::Misc | BuiltinImplSource::Trivial, data) => {
12831265
let tcx = selcx.tcx();
12841266
let trait_def_id = obligation.predicate.trait_def_id(tcx);
1285-
if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) {
1267+
let progress = if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) {
12861268
confirm_coroutine_candidate(selcx, obligation, data)
12871269
} else if tcx.is_lang_item(trait_def_id, LangItem::Future) {
12881270
confirm_future_candidate(selcx, obligation, data)
@@ -1304,7 +1286,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
13041286
confirm_async_fn_kind_helper_candidate(selcx, obligation, data)
13051287
} else {
13061288
confirm_builtin_candidate(selcx, obligation, data)
1307-
}
1289+
};
1290+
Ok(Projected::Progress(progress))
13081291
}
13091292
ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)
13101293
| ImplSource::Param(..)
@@ -2000,7 +1983,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20001983
selcx: &mut SelectionContext<'cx, 'tcx>,
20011984
obligation: &ProjectionTermObligation<'tcx>,
20021985
impl_impl_source: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
2003-
) -> Progress<'tcx> {
1986+
) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
20041987
let tcx = selcx.tcx();
20051988

20061989
let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source;
@@ -2011,19 +1994,33 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20111994
let param_env = obligation.param_env;
20121995
let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
20131996
Ok(assoc_ty) => assoc_ty,
2014-
Err(guar) => return Progress::error(tcx, guar),
1997+
Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))),
20151998
};
1999+
2000+
// This means that the impl is missing a definition for the
2001+
// associated type. This is either because the associate item
2002+
// has impossible-to-satisfy predicates (since those were
2003+
// allowed in <https://github.com/rust-lang/rust/pull/135480>),
2004+
// or because the impl is literally missing the definition.
20162005
if !assoc_ty.item.defaultness(tcx).has_value() {
2017-
// This means that the impl is missing a definition for the
2018-
// associated type. This error will be reported by the type
2019-
// checker method `check_impl_items_against_trait`, so here we
2020-
// just return Error.
20212006
debug!(
20222007
"confirm_impl_candidate: no associated type {:?} for {:?}",
20232008
assoc_ty.item.name, obligation.predicate
20242009
);
2025-
return Progress { term: Ty::new_misc_error(tcx).into(), obligations: nested };
2010+
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
2011+
// We treat this projection as rigid here, which is represented via
2012+
// `Projected::NoProgress`. This will ensure that the projection is
2013+
// checked for well-formedness, and it's either satisfied by a trivial
2014+
// where clause in its env or it results in an error.
2015+
return Ok(Projected::NoProgress(obligation.predicate.to_term(tcx)));
2016+
} else {
2017+
return Ok(Projected::Progress(Progress {
2018+
term: Ty::new_misc_error(tcx).into(),
2019+
obligations: nested,
2020+
}));
2021+
}
20262022
}
2023+
20272024
// If we're trying to normalize `<Vec<u32> as X>::A<S>` using
20282025
//`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
20292026
//
@@ -2033,6 +2030,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20332030
let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args);
20342031
let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node);
20352032
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
2033+
20362034
let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const {
20372035
let did = assoc_ty.item.def_id;
20382036
let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did);
@@ -2041,7 +2039,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20412039
} else {
20422040
tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into())
20432041
};
2044-
if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
2042+
2043+
let progress = if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
20452044
let err = Ty::new_error_with_message(
20462045
tcx,
20472046
obligation.cause.span,
@@ -2051,7 +2050,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20512050
} else {
20522051
assoc_ty_own_obligations(selcx, obligation, &mut nested);
20532052
Progress { term: term.instantiate(tcx, args), obligations: nested }
2054-
}
2053+
};
2054+
Ok(Projected::Progress(progress))
20552055
}
20562056

20572057
// Get obligations corresponding to the predicates from the where-clause of the

compiler/rustc_ty_utils/src/ty.rs

+57
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_hir as hir;
33
use rustc_hir::LangItem;
44
use rustc_hir::def::DefKind;
55
use rustc_index::bit_set::DenseBitSet;
6+
use rustc_infer::infer::TyCtxtInferExt;
67
use rustc_middle::bug;
78
use rustc_middle::query::Providers;
89
use rustc_middle::ty::{
@@ -312,6 +313,61 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> DenseBitSe
312313
unsizing_params
313314
}
314315

316+
fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId) -> bool {
317+
debug_assert_eq!(tcx.def_kind(impl_def_id), DefKind::Impl { of_trait: true });
318+
319+
let infcx = tcx.infer_ctxt().ignoring_regions().build(ty::TypingMode::non_body_analysis());
320+
321+
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
322+
let cause = traits::ObligationCause::dummy();
323+
let param_env = tcx.param_env(impl_def_id);
324+
325+
let tail = tcx.struct_tail_raw(
326+
tcx.type_of(impl_def_id).instantiate_identity(),
327+
|ty| {
328+
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
329+
Ty::new_error_with_message(
330+
tcx,
331+
tcx.def_span(impl_def_id),
332+
"struct tail should be computable",
333+
)
334+
})
335+
},
336+
|| (),
337+
);
338+
339+
match tail.kind() {
340+
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
341+
ty::Bool
342+
| ty::Char
343+
| ty::Int(_)
344+
| ty::Uint(_)
345+
| ty::Float(_)
346+
| ty::Adt(_, _)
347+
| ty::Foreign(_)
348+
| ty::Array(_, _)
349+
| ty::Pat(_, _)
350+
| ty::RawPtr(_, _)
351+
| ty::Ref(_, _, _)
352+
| ty::FnDef(_, _)
353+
| ty::FnPtr(_, _)
354+
| ty::UnsafeBinder(_)
355+
| ty::Closure(_, _)
356+
| ty::CoroutineClosure(_, _)
357+
| ty::Coroutine(_, _)
358+
| ty::CoroutineWitness(_, _)
359+
| ty::Never
360+
| ty::Tuple(_)
361+
| ty::Alias(_, _)
362+
| ty::Param(_)
363+
| ty::Bound(_, _)
364+
| ty::Placeholder(_)
365+
| ty::Infer(_)
366+
| ty::Error(_)
367+
| ty::Dynamic(_, _, ty::DynStar) => false,
368+
}
369+
}
370+
315371
pub(crate) fn provide(providers: &mut Providers) {
316372
*providers = Providers {
317373
asyncness,
@@ -320,6 +376,7 @@ pub(crate) fn provide(providers: &mut Providers) {
320376
param_env_normalized_for_post_analysis,
321377
defaultness,
322378
unsizing_params_for_adt,
379+
impl_self_is_guaranteed_unsized,
323380
..*providers
324381
};
325382
}

0 commit comments

Comments
 (0)