Skip to content

hir_analysis: add missing sizedness bounds #142712

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
| PredicateFilter::SelfOnly
| PredicateFilter::SelfTraitThatDefines(_)
| PredicateFilter::SelfAndAssociatedTypeBounds => {
icx.lowerer().add_sizedness_bounds(
&mut bounds,
self_param_ty,
superbounds,
None,
Some(trait_def_id),
item.span,
);
icx.lowerer().add_default_super_traits(
trait_def_id,
&mut bounds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

self.add_default_traits(&mut user_written_bounds, dummy_self, &ast_bounds, None, span);

let (elaborated_trait_bounds, elaborated_projection_bounds) =
let (mut elaborated_trait_bounds, elaborated_projection_bounds) =
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());

// FIXME(sized-hierarchy): https://github.com/rust-lang/rust/pull/142712#issuecomment-3013231794
let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
elaborated_trait_bounds.retain(|(pred, _)| pred.def_id() != meta_sized_did);

let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
.into_iter()
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.is_default_trait(def_id)
}

fn is_sizedness_trait(self, def_id: DefId) -> bool {
self.is_sizedness_trait(def_id)
}

fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
}
Expand Down Expand Up @@ -1652,6 +1656,10 @@ impl<'tcx> TyCtxt<'tcx> {
.any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id))
}

pub fn is_sizedness_trait(self, def_id: DefId) -> bool {
matches!(self.as_lang_item(def_id), Some(LangItem::Sized | LangItem::MetaSized))
}

/// Returns a range of the start/end indices specified with the
/// `rustc_layout_scalar_valid_range` attribute.
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub use rustc_type_ir::fast_reject::DeepRejectCtxt;
)]
use rustc_type_ir::inherent;
pub use rustc_type_ir::relate::VarianceDiagInfo;
pub use rustc_type_ir::solve::SizedTraitKind;
pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind};
pub use rustc_type_ir::*;
#[allow(hidden_glob_reexports, unused_imports)]
use rustc_type_ir::{InferCtxtLike, Interner};
Expand Down
41 changes: 28 additions & 13 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_type_ir::data_structures::IndexSet;
use rustc_type_ir::fast_reject::DeepRejectCtxt;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
use rustc_type_ir::solve::{CandidatePreferenceMode, CanonicalResponse, SizedTraitKind};
use rustc_type_ir::{
self as ty, Interner, Movability, TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode,
Upcast as _, elaborate,
Expand Down Expand Up @@ -1343,6 +1343,7 @@ where
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_trait_candidates(
&mut self,
candidate_preference_mode: CandidatePreferenceMode,
mut candidates: Vec<Candidate<I>>,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
if let TypingMode::Coherence = self.typing_mode() {
Expand All @@ -1368,6 +1369,26 @@ where
return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
}

let potential_alias_bound_response =
candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)).then(|| {
let alias_bounds: Vec<_> = candidates
.iter()
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
.map(|c| c.result)
.collect();
if let Some(response) = self.try_merge_responses(&alias_bounds) {
(response, Some(TraitGoalProvenVia::AliasBound))
} else {
(self.bail_with_ambiguity(&alias_bounds), None)
}
});

if matches!(candidate_preference_mode, CandidatePreferenceMode::Marker)
&& let Some(alias_bound_response) = potential_alias_bound_response
{
return Ok(alias_bound_response);
}

// If there are non-global where-bounds, prefer where-bounds
// (including global ones) over everything else.
let has_non_global_where_bounds = candidates
Expand All @@ -1386,17 +1407,8 @@ where
};
}

if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
let alias_bounds: Vec<_> = candidates
.iter()
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
.map(|c| c.result)
.collect();
return if let Some(response) = self.try_merge_responses(&alias_bounds) {
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
} else {
Ok((self.bail_with_ambiguity(&alias_bounds), None))
};
if let Some(response) = potential_alias_bound_response {
return Ok(response);
}

self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
Expand Down Expand Up @@ -1431,7 +1443,10 @@ where
goal: Goal<I, TraitPredicate<I>>,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
self.merge_trait_candidates(candidates)

let candidate_preference_mode =
CandidatePreferenceMode::compute(self.cx(), goal.predicate.def_id());
self.merge_trait_candidates(candidate_preference_mode, candidates)
}

fn try_stall_coroutine_witness(
Expand Down
24 changes: 0 additions & 24 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>,
idx: usize,
) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let tcx = self.tcx();

let placeholder_trait_predicate =
self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref;
let placeholder_self_ty = self.infcx.shallow_resolve(placeholder_trait_predicate.self_ty());
Expand Down Expand Up @@ -194,28 +192,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|_| SelectionError::Unimplemented)?,
);

// FIXME(compiler-errors): I don't think this is needed.
if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() {
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate_own(tcx, alias_ty.args);
for (predicate, _) in predicates {
let normalized = normalize_with_depth_to(
self,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
predicate,
&mut obligations,
);
obligations.push(Obligation::with_depth(
self.tcx(),
obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
normalized,
));
}
}

Ok(obligations)
}

Expand Down
29 changes: 22 additions & 7 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::TypeErrorToStringExt;
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
use rustc_middle::ty::{
self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt,
TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature,
self, CandidatePreferenceMode, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate,
SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate,
may_use_unstable_feature,
};
use rustc_span::{Symbol, sym};
use tracing::{debug, instrument, trace};
Expand Down Expand Up @@ -473,7 +474,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
} else {
let has_non_region_infer = stack.obligation.predicate.has_non_region_infer();
if let Some(candidate) = self.winnow_candidates(has_non_region_infer, candidates) {
let candidate_preference_mode =
CandidatePreferenceMode::compute(self.tcx(), stack.obligation.predicate.def_id());
if let Some(candidate) =
self.winnow_candidates(has_non_region_infer, candidate_preference_mode, candidates)
{
self.filter_reservation_impls(candidate)
} else {
Ok(None)
Expand Down Expand Up @@ -1822,6 +1827,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
fn winnow_candidates(
&mut self,
has_non_region_infer: bool,
candidate_preference_mode: CandidatePreferenceMode,
mut candidates: Vec<EvaluatedCandidate<'tcx>>,
) -> Option<SelectionCandidate<'tcx>> {
if candidates.len() == 1 {
Expand Down Expand Up @@ -1875,6 +1881,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
break;
}

let alias_bound = candidates
.iter()
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });

if matches!(candidate_preference_mode, CandidatePreferenceMode::Marker) {
match alias_bound {
Some(Some(index)) => return Some(ProjectionCandidate(index)),
Some(None) => {}
None => return None,
}
}

// The next highest priority is for non-global where-bounds. However, while we don't
// prefer global where-clauses here, we do bail with ambiguity when encountering both
// a global and a non-global where-clause.
Expand Down Expand Up @@ -1908,10 +1927,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// fairly arbitrary but once again necessary for backwards compatibility.
// If there are multiple applicable candidates which don't affect type inference,
// choose the one with the lowest index.
let alias_bound = candidates
.iter()
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
match alias_bound {
Some(Some(index)) => return Some(ProjectionCandidate(index)),
Some(None) => {}
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_trait_selection/src/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,13 +379,6 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
_ => return false,
};

// FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature
// while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs`
// is pending a proper fix
if !tcx.features().sized_hierarchy() && matches!(sizedness, SizedTraitKind::MetaSized) {
return true;
}

if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
debug!("fast path -- trivial sizedness");
return true;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_type_ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ pub trait Interner:

fn is_default_trait(self, def_id: Self::DefId) -> bool;

fn is_sizedness_trait(self, def_id: Self::DefId) -> bool;

fn as_lang_item(self, def_id: Self::DefId) -> Option<TraitSolverLangItem>;

fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_type_ir/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,30 @@ pub struct PredefinedOpaquesData<I: Interner> {
pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
}

/// Which trait candidates should be preferred over other candidates? By default, prefer where
/// bounds over alias bounds. For marker traits, prefer alias bounds over where bounds.
#[derive(Clone, Copy, Debug)]
pub enum CandidatePreferenceMode {
/// Prefers where bounds over alias bounds
Default,
/// Prefers alias bounds over where bounds
Marker,
}

impl CandidatePreferenceMode {
/// Given `trait_def_id`, which candidate preference mode should be used?
pub fn compute<I: Interner>(cx: I, trait_def_id: I::DefId) -> CandidatePreferenceMode {
let is_sizedness_or_auto_or_default_goal = cx.is_sizedness_trait(trait_def_id)
|| cx.trait_is_auto(trait_def_id)
|| cx.is_default_trait(trait_def_id);
if is_sizedness_or_auto_or_default_goal {
CandidatePreferenceMode::Marker
} else {
CandidatePreferenceMode::Default
}
}
}

/// Possible ways the given goal can be proven.
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
pub enum CandidateSource<I: Interner> {
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ extern "C" {
}

const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) };
//~^ ERROR `extern type` does not have known layout
//~^ ERROR: the size for values of type `Opaque` cannot be known
const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
//~^ ERROR `extern type` does not have known layout
//~^ ERROR: the size for values of type `Opaque` cannot be known

fn main() {}
38 changes: 31 additions & 7 deletions tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,39 @@
error[E0080]: `extern type` does not have known layout
--> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:31
error[E0277]: the size for values of type `Opaque` cannot be known
--> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:43
|
LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_SIZE` failed here
| ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque`
| |
| required by a bound introduced by this call
|
= note: the trait bound `Opaque: MetaSized` is not satisfied
note: required by a bound in `std::intrinsics::size_of_val`
--> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
help: consider borrowing here
|
LL | const _SIZE: usize = unsafe { size_of_val(&(&4 as *const i32 as *const Opaque)) };
| ++ +
LL | const _SIZE: usize = unsafe { size_of_val(&mut (&4 as *const i32 as *const Opaque)) };
| ++++++ +

error[E0080]: `extern type` does not have known layout
--> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:32
error[E0277]: the size for values of type `Opaque` cannot be known
--> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:45
|
LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque`
| |
| required by a bound introduced by this call
|
= note: the trait bound `Opaque: MetaSized` is not satisfied
note: required by a bound in `std::intrinsics::align_of_val`
--> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
help: consider borrowing here
|
LL | const _ALIGN: usize = unsafe { align_of_val(&(&4 as *const i32 as *const Opaque)) };
| ++ +
LL | const _ALIGN: usize = unsafe { align_of_val(&mut (&4 as *const i32 as *const Opaque)) };
| ++++++ +

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0080`.
For more information about this error, try `rustc --explain E0277`.
3 changes: 2 additions & 1 deletion tests/ui/dyn-compatibility/assoc_type_bounds_sized_used.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ trait Bop {

fn bop<T: Bop + ?Sized>() {
let _ = <T as Bop>::Bar::default();
//~^ ERROR: trait bounds were not satisfied
//~^ ERROR: the size for values of type `T` cannot be known at compilation time
//~| ERROR: the size for values of type `T` cannot be known at compilation time
//~| ERROR: the size for values of type `T` cannot be known at compilation time
}

Expand Down
Loading