Skip to content

[WIP] change overflow to be non-fatal #104534

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

Closed
wants to merge 5 commits into from
Closed
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
16 changes: 10 additions & 6 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1745,19 +1745,23 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,

match in_elem.kind() {
ty::RawPtr(p) => {
let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
let (metadata, check_sized) =
p.ty.ptr_metadata_ty(bx.tcx, |ty| {
Ok(bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty))
})
.unwrap();
assert!(!check_sized); // we are in codegen, so we shouldn't see these types
require!(metadata.is_unit(), "cannot cast fat pointer `{}`", in_elem)
}
_ => return_error!("expected pointer, got `{}`", in_elem),
}
match out_elem.kind() {
ty::RawPtr(p) => {
let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
let (metadata, check_sized) =
p.ty.ptr_metadata_ty(bx.tcx, |ty| {
Ok(bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty))
})
.unwrap();
assert!(!check_sized); // we are in codegen, so we shouldn't see these types
require!(metadata.is_unit(), "cannot cast to fat pointer `{}`", out_elem)
}
20 changes: 11 additions & 9 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
@@ -177,15 +177,17 @@ fn get_info_on_unsized_field<'tcx>(
tcx: TyCtxt<'tcx>,
) -> (Ty<'tcx>, usize) {
let mut last_valtree = valtree;
let tail = tcx.struct_tail_with_normalize(
ty,
|ty| ty,
|| {
let branches = last_valtree.unwrap_branch();
last_valtree = branches[branches.len() - 1];
debug!(?branches, ?last_valtree);
},
);
let tail = tcx
.struct_tail_with_normalize(
ty,
|ty| Ok(ty),
|| {
let branches = last_valtree.unwrap_branch();
last_valtree = branches[branches.len() - 1];
debug!(?branches, ?last_valtree);
},
)
.unwrap();
let unsized_inner_ty = match tail.kind() {
ty::Slice(t) => *t,
ty::Str => tail,
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
@@ -770,14 +770,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}

match implsrc {
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
Ok(Ok(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
debug!(
"const_trait_impl: provided {:?} via where-clause in {:?}",
trait_ref, param_env
);
return;
}
Ok(Some(ImplSource::UserDefined(data))) => {
Ok(Ok(ImplSource::UserDefined(data))) => {
let callee_name = tcx.item_name(callee);
if let Some(&did) = tcx
.associated_item_def_ids(data.impl_def_id)
Original file line number Diff line number Diff line change
@@ -160,7 +160,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
let mut selcx = SelectionContext::new(&infcx);
let implsrc = selcx.select(&obligation);

if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
if let Ok(Ok(ImplSource::UserDefined(data))) = implsrc {
let span = tcx.def_span(data.impl_def_id);
err.span_note(span, "impl defined here, but it is not `const`");
}
Original file line number Diff line number Diff line change
@@ -170,7 +170,7 @@ impl Qualif for NeedsNonConstDrop {

let infcx = cx.tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
let Ok(Ok(impl_src)) = selcx.select(&obligation) else {
// If we couldn't select a const destruct candidate, then it's bad
return true;
};
19 changes: 16 additions & 3 deletions compiler/rustc_data_structures/src/obligation_forest/mod.rs
Original file line number Diff line number Diff line change
@@ -107,6 +107,12 @@ pub trait ObligationProcessor {
obligation: &mut Self::Obligation,
) -> ProcessResult<Self::Obligation, Self::Error>;

fn update_obligation_depth(
&mut self,
obligation: &Self::Obligation,
child: &mut Self::Obligation,
);

/// As we do the cycle check, we invoke this callback when we
/// encounter an actual cycle. `cycle` is an iterator that starts
/// at the start of the cycle in the stack and walks **toward the
@@ -375,13 +381,16 @@ impl<O: ForestObligation> ObligationForest<O> {
}

/// Converts all remaining obligations to the given error.
pub fn to_errors<E: Clone>(&mut self, error: E) -> Vec<Error<O, E>> {
pub fn to_errors<E>(&mut self, mut mk_error: impl FnMut(&O) -> E) -> Vec<Error<O, E>> {
let errors = self
.nodes
.iter()
.enumerate()
.filter(|(_index, node)| node.state.get() == NodeState::Pending)
.map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) })
.map(|(index, node)| Error {
error: mk_error(&node.obligation),
backtrace: self.error_at(index),
})
.collect();

self.compress(|_| assert!(false));
@@ -447,11 +456,15 @@ impl<O: ForestObligation> ObligationForest<O> {
ProcessResult::Unchanged => {
// No change in state.
}
ProcessResult::Changed(children) => {
ProcessResult::Changed(mut children) => {
// We are not (yet) stalled.
has_changed = true;
node.state.set(NodeState::Success);

for child in &mut children {
processor.update_obligation_depth(&node.obligation, child);
}

for child in children {
let st = self.register_obligation_at(child, Some(index));
if let Err(()) = st {
10 changes: 6 additions & 4 deletions compiler/rustc_data_structures/src/obligation_forest/tests.rs
Original file line number Diff line number Diff line change
@@ -70,6 +70,8 @@ where
true
}

fn update_obligation_depth(&mut self, _: &Self::Obligation, _: &mut Self::Obligation) {}

fn process_obligation(
&mut self,
obligation: &mut Self::Obligation,
@@ -256,7 +258,7 @@ fn to_errors_no_throw() {
));
assert_eq!(ok.len(), 0);
assert_eq!(err.len(), 0);
let errors = forest.to_errors(());
let errors = forest.to_errors(|_| ());
assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
@@ -308,7 +310,7 @@ fn diamond() {
assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
assert_eq!(err.len(), 0);

let errors = forest.to_errors(());
let errors = forest.to_errors(|_| ());
assert_eq!(errors.len(), 0);

forest.register_obligation("A'");
@@ -353,7 +355,7 @@ fn diamond() {
vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }]
);

let errors = forest.to_errors(());
let errors = forest.to_errors(|_| ());
assert_eq!(errors.len(), 0);
}

@@ -446,7 +448,7 @@ fn orphan() {
assert_eq!(ok.len(), 0);
assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]);

let errors = forest.to_errors(());
let errors = forest.to_errors(|_| ());
assert_eq!(errors.len(), 0);
}

Original file line number Diff line number Diff line change
@@ -74,6 +74,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::specialization_graph::Node;
use rustc_infer::traits::Overflow;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
@@ -377,7 +378,9 @@ fn check_predicates<'tcx>(
0,
arg,
span,
true,
)
.unwrap_or_else(|Overflow| bug!("impossible non-fatal overflow"))
.unwrap();

assert!(!obligations.needs_infer());
5 changes: 3 additions & 2 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
@@ -671,7 +671,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
};
match selcx.select(&obligation.with(trait_pred)) {
// Uncertain or unimplemented.
Ok(None) => {
Ok(Err(true)) => self.err_ctxt().report_overflow_error(&obligation, true),
Ok(Err(false)) => {
if trait_pred.def_id() == unsize_did {
let trait_pred = self.resolve_vars_if_possible(trait_pred);
let self_ty = trait_pred.skip_binder().self_ty();
@@ -712,7 +713,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// be silent, as it causes a type mismatch later.
}

Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()),
Ok(Ok(impl_source)) => queue.extend(impl_source.nested_obligations()),
}
}

2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
@@ -2159,7 +2159,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}),
);
match SelectionContext::new(&self).select(&obligation) {
Ok(Some(traits::ImplSource::UserDefined(impl_source))) => {
Ok(Ok(traits::ImplSource::UserDefined(impl_source))) => {
Some(impl_source.impl_def_id)
}
_ => None,
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
@@ -1447,7 +1447,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
.define_opaque_types(false)
.sup(candidate.xform_self_ty, self_ty);
match self.select_trait_candidate(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
Ok(Ok(traits::ImplSource::UserDefined(ref impl_data))) => {
// If only a single impl matches, make the error message point
// to that impl.
CandidateSource::Impl(impl_data.impl_def_id)
@@ -1566,7 +1566,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if self.probe(|_| {
match self.select_trait_candidate(trait_ref) {
Err(_) => return true,
Ok(Some(impl_source))
Ok(Ok(impl_source))
if !impl_source.borrow_nested_obligations().is_empty() =>
{
for obligation in impl_source.borrow_nested_obligations() {
8 changes: 0 additions & 8 deletions compiler/rustc_infer/src/traits/engine.rs
Original file line number Diff line number Diff line change
@@ -8,14 +8,6 @@ use super::FulfillmentError;
use super::{ObligationCause, PredicateObligation};

pub trait TraitEngine<'tcx>: 'tcx {
fn normalize_projection_type(
&mut self,
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
) -> Ty<'tcx>;

/// Requires that `ty` must implement the trait with `def_id` in
/// the given environment. This trait must not have any type
/// parameters (except for `Self`).
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -111,7 +111,7 @@ pub struct FulfillmentError<'tcx> {
pub root_obligation: PredicateObligation<'tcx>,
}

#[derive(Clone)]
#[derive(Debug, Clone)]
pub enum FulfillmentErrorCode<'tcx> {
/// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
CodeCycle(Vec<Obligation<'tcx, ty::Predicate<'tcx>>>),
@@ -120,6 +120,7 @@ pub enum FulfillmentErrorCode<'tcx> {
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
CodeAmbiguity,
CodeOverflow,
}

impl<'tcx, O> Obligation<'tcx, O> {
8 changes: 7 additions & 1 deletion compiler/rustc_infer/src/traits/project.rs
Original file line number Diff line number Diff line change
@@ -90,6 +90,7 @@ impl<'tcx> ProjectionCacheKey<'tcx> {
pub enum ProjectionCacheEntry<'tcx> {
InProgress,
Ambiguous,
Overflow,
Recur,
Error,
NormalizedTy {
@@ -184,7 +185,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
key, value
);
let mut map = self.map();
if let Some(ProjectionCacheEntry::Recur) = map.get(&key) {
if let Some(ProjectionCacheEntry::Recur | ProjectionCacheEntry::Overflow) = map.get(&key) {
debug!("Not overwriting Recur");
return;
}
@@ -223,6 +224,11 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
})
}

pub fn overflow(&mut self, key: ProjectionCacheKey<'tcx>) {
let fresh = self.map().insert(key, ProjectionCacheEntry::Overflow);
assert!(!fresh, "never started projecting `{:?}", key);
}

/// Indicates that trying to normalize `key` resulted in
/// ambiguity. No point in trying it again then until we gain more
/// type information (in which case, the "fully resolved" key will
17 changes: 0 additions & 17 deletions compiler/rustc_infer/src/traits/structural_impls.rs
Original file line number Diff line number Diff line change
@@ -35,23 +35,6 @@ impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> {
}
}

impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
super::CodeSelectionError(ref e) => write!(f, "{:?}", e),
super::CodeProjectionError(ref e) => write!(f, "{:?}", e),
super::CodeSubtypeError(ref a, ref b) => {
write!(f, "CodeSubtypeError({:?}, {:?})", a, b)
}
super::CodeConstEquateError(ref a, ref b) => {
write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
}
super::CodeAmbiguity => write!(f, "Ambiguity"),
super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle),
}
}
}

impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MismatchedProjectionTypes({:?})", self.err)
22 changes: 5 additions & 17 deletions compiler/rustc_middle/src/infer/canonical.rs
Original file line number Diff line number Diff line change
@@ -237,30 +237,18 @@ pub enum Certainty {
/// canonical form will be different, making this a distinct
/// query.
Ambiguous,
}

impl Certainty {
pub fn is_proven(&self) -> bool {
match self {
Certainty::Proven => true,
Certainty::Ambiguous => false,
}
}
Overflow,
}

impl<'tcx, R> QueryResponse<'tcx, R> {
pub fn is_proven(&self) -> bool {
self.certainty.is_proven()
pub fn certainty(&self) -> Certainty {
self.certainty
}
}

impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
pub fn is_proven(&self) -> bool {
self.value.is_proven()
}

pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
pub fn certainty(&self) -> Certainty {
self.value.certainty()
}
}

2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1907,7 +1907,7 @@ rustc_queries! {
/// `infcx.predicate_must_hold()` instead.
query evaluate_obligation(
goal: CanonicalPredicateGoal<'tcx>
) -> Result<traits::EvaluationResult, traits::OverflowError> {
) -> traits::EvaluationResult {
desc { "evaluating trait selection obligation `{}`", goal.value.value }
}

Loading