Auto merge of #131495 - matthiaskrgr:rollup-lwf2u4i, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #130625 (Fix a few relative paths in rustc doc) - #131397 (fix/update teach_note from 'escaping mutable ref/ptr' const-check) - #131479 (Apple: Avoid redundant `-Wl,-dylib` flag when linking) - #131480 (Fix hardcoded strip path when cross-compiling from Linux to Darwin) - #131482 (structurally resolve adts and tuples expectations too) - #131484 (Add myself back to review rotation) - #131491 (impossible obligations fast path) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
4cc494bbfe
@ -1087,7 +1087,9 @@ fn link_natively(
|
||||
let strip = sess.opts.cg.strip;
|
||||
|
||||
if sess.target.is_like_osx {
|
||||
let stripcmd = "/usr/bin/strip";
|
||||
// Use system `strip` when running on host macOS.
|
||||
// <https://github.com/rust-lang/rust/pull/130781>
|
||||
let stripcmd = if cfg!(target_os = "macos") { "/usr/bin/strip" } else { "strip" };
|
||||
match (strip, crate_type) {
|
||||
(Strip::Debuginfo, _) => {
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S"))
|
||||
|
@ -404,12 +404,14 @@ impl<'a> GccLinker<'a> {
|
||||
fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
|
||||
// On mac we need to tell the linker to let this library be rpathed
|
||||
if self.sess.target.is_like_osx {
|
||||
if !self.is_ld {
|
||||
if self.is_cc() {
|
||||
// `-dynamiclib` makes `cc` pass `-dylib` to the linker.
|
||||
self.cc_arg("-dynamiclib");
|
||||
} else {
|
||||
self.link_arg("-dylib");
|
||||
// Clang also sets `-dynamic`, but that's implied by `-dylib`, so unnecessary.
|
||||
}
|
||||
|
||||
self.link_arg("-dylib");
|
||||
|
||||
// Note that the `osx_rpath_install_name` option here is a hack
|
||||
// purely to support bootstrap right now, we should get a more
|
||||
// principled solution at some point to force the compiler to pass
|
||||
|
@ -134,14 +134,16 @@ const_eval_incompatible_return_types =
|
||||
const_eval_incompatible_types =
|
||||
calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
|
||||
|
||||
const_eval_interior_mutable_data_refer =
|
||||
const_eval_interior_mutable_ref_escaping =
|
||||
{const_eval_const_context}s cannot refer to interior mutable data
|
||||
.label = this borrow of an interior mutable value may end up in the final value
|
||||
.help = to fix this, the value can be extracted to a separate `static` item and then referenced
|
||||
.teach_note =
|
||||
A constant containing interior mutable data behind a reference can allow you to modify that data.
|
||||
This would make multiple uses of a constant to be able to see different values and allow circumventing
|
||||
the `Send` and `Sync` requirements for shared mutable data, which is unsound.
|
||||
References that escape into the final value of a constant or static must be immutable.
|
||||
This is to avoid accidentally creating shared mutable state.
|
||||
|
||||
|
||||
If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
|
||||
|
||||
const_eval_intern_kind = {$kind ->
|
||||
[static] static
|
||||
@ -229,6 +231,24 @@ const_eval_modified_global =
|
||||
|
||||
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
|
||||
|
||||
const_eval_mutable_raw_escaping =
|
||||
raw mutable pointers are not allowed in the final value of {const_eval_const_context}s
|
||||
.teach_note =
|
||||
Pointers that escape into the final value of a constant or static must be immutable.
|
||||
This is to avoid accidentally creating shared mutable state.
|
||||
|
||||
|
||||
If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
|
||||
|
||||
const_eval_mutable_ref_escaping =
|
||||
mutable references are not allowed in the final value of {const_eval_const_context}s
|
||||
.teach_note =
|
||||
References that escape into the final value of a constant or static must be immutable.
|
||||
This is to avoid accidentally creating shared mutable state.
|
||||
|
||||
|
||||
If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
|
||||
|
||||
const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
|
||||
const_eval_non_const_fmt_macro_call =
|
||||
cannot call non-const formatting macro in {const_eval_const_context}s
|
||||
@ -364,30 +384,11 @@ const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in
|
||||
const_eval_unallowed_heap_allocations =
|
||||
allocations are not allowed in {const_eval_const_context}s
|
||||
.label = allocation not allowed in {const_eval_const_context}s
|
||||
.teach_note = The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time.
|
||||
.teach_note =
|
||||
The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created.
|
||||
|
||||
const_eval_unallowed_inline_asm =
|
||||
inline assembly is not allowed in {const_eval_const_context}s
|
||||
const_eval_unallowed_mutable_raw =
|
||||
raw mutable pointers are not allowed in the final value of {const_eval_const_context}s
|
||||
.teach_note =
|
||||
References in statics and constants may only refer to immutable values.
|
||||
|
||||
|
||||
Statics are shared everywhere, and if they refer to mutable data one might violate memory
|
||||
safety since holding multiple mutable references to shared data is not allowed.
|
||||
|
||||
|
||||
If you really want global mutable state, try using static mut or a global UnsafeCell.
|
||||
|
||||
const_eval_unallowed_mutable_refs =
|
||||
mutable references are not allowed in the final value of {const_eval_const_context}s
|
||||
.teach_note =
|
||||
Statics are shared everywhere, and if they refer to mutable data one might violate memory
|
||||
safety since holding multiple mutable references to shared data is not allowed.
|
||||
|
||||
|
||||
If you really want global mutable state, try using static mut or a global UnsafeCell.
|
||||
|
||||
const_eval_unallowed_op_in_const_context =
|
||||
{$msg}
|
||||
|
@ -666,6 +666,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// This can be called on stable via the `vec!` macro.
|
||||
if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) {
|
||||
self.check_op(ops::HeapAllocation);
|
||||
return;
|
||||
|
@ -402,7 +402,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow {
|
||||
DiagImportance::Secondary
|
||||
}
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::InteriorMutableDataRefer {
|
||||
ccx.dcx().create_err(errors::InteriorMutableRefEscaping {
|
||||
span,
|
||||
opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)),
|
||||
kind: ccx.const_kind(),
|
||||
@ -430,12 +430,12 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
match self.0 {
|
||||
hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw {
|
||||
hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::MutableRawEscaping {
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
teach: ccx.tcx.sess.teach(E0764),
|
||||
}),
|
||||
hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs {
|
||||
hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping {
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
teach: ccx.tcx.sess.teach(E0764),
|
||||
|
@ -118,8 +118,8 @@ pub(crate) struct UnstableConstFn {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unallowed_mutable_refs, code = E0764)]
|
||||
pub(crate) struct UnallowedMutableRefs {
|
||||
#[diag(const_eval_mutable_ref_escaping, code = E0764)]
|
||||
pub(crate) struct MutableRefEscaping {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub kind: ConstContext,
|
||||
@ -128,8 +128,8 @@ pub(crate) struct UnallowedMutableRefs {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unallowed_mutable_raw, code = E0764)]
|
||||
pub(crate) struct UnallowedMutableRaw {
|
||||
#[diag(const_eval_mutable_raw_escaping, code = E0764)]
|
||||
pub(crate) struct MutableRawEscaping {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub kind: ConstContext,
|
||||
@ -181,8 +181,8 @@ pub(crate) struct UnallowedInlineAsm {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_interior_mutable_data_refer, code = E0492)]
|
||||
pub(crate) struct InteriorMutableDataRefer {
|
||||
#[diag(const_eval_interior_mutable_ref_escaping, code = E0492)]
|
||||
pub(crate) struct InteriorMutableRefEscaping {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
|
@ -33,6 +33,7 @@ pub mod weak_lang_items;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use hir::*;
|
||||
pub use hir_id::*;
|
||||
pub use lang_items::{LangItem, LanguageItems};
|
||||
|
@ -1783,7 +1783,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let flds = expected.only_has_type(self).and_then(|ty| {
|
||||
let ty = self.resolve_vars_with_obligations(ty);
|
||||
let ty = self.try_structurally_resolve_type(expr.span, ty);
|
||||
match ty.kind() {
|
||||
ty::Tuple(flds) => Some(&flds[..]),
|
||||
_ => None,
|
||||
@ -1861,7 +1861,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let adt_ty = self.resolve_vars_with_obligations(adt_ty);
|
||||
let adt_ty = self.try_structurally_resolve_type(span, adt_ty);
|
||||
let adt_ty_hint = expected.only_has_type(self).and_then(|expected| {
|
||||
self.fudge_inference_if_ok(|| {
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
|
@ -17,6 +17,7 @@ mod vec;
|
||||
pub use idx::Idx;
|
||||
pub use rustc_index_macros::newtype_index;
|
||||
pub use slice::IndexSlice;
|
||||
#[doc(no_inline)]
|
||||
pub use vec::IndexVec;
|
||||
|
||||
/// Type size assertion. The first argument is a type and the second argument is its expected size.
|
||||
|
@ -18,8 +18,8 @@ use crate::solve::inspect::{self, ProofTreeBuilder};
|
||||
use crate::solve::search_graph::SearchGraph;
|
||||
use crate::solve::{
|
||||
CanonicalInput, CanonicalResponse, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind,
|
||||
GoalSource, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult,
|
||||
SolverMode,
|
||||
GoalSource, HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData,
|
||||
QueryResult, SolverMode,
|
||||
};
|
||||
|
||||
pub(super) mod canonical;
|
||||
@ -126,11 +126,31 @@ pub enum GenerateProofTree {
|
||||
}
|
||||
|
||||
pub trait SolverDelegateEvalExt: SolverDelegate {
|
||||
/// Evaluates a goal from **outside** of the trait solver.
|
||||
///
|
||||
/// Using this while inside of the solver is wrong as it uses a new
|
||||
/// search graph which would break cycle detection.
|
||||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<Self::Interner>>);
|
||||
) -> (
|
||||
Result<(HasChanged, Certainty), NoSolution>,
|
||||
Option<inspect::GoalEvaluation<Self::Interner>>,
|
||||
);
|
||||
|
||||
/// Check whether evaluating `goal` with a depth of `root_depth` may
|
||||
/// succeed. This only returns `false` if the goal is guaranteed to
|
||||
/// not hold. In case evaluation overflows and fails with ambiguity this
|
||||
/// returns `true`.
|
||||
///
|
||||
/// This is only intended to be used as a performance optimization
|
||||
/// in coherence checking.
|
||||
fn root_goal_may_hold_with_depth(
|
||||
&self,
|
||||
root_depth: usize,
|
||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||
) -> bool;
|
||||
|
||||
// FIXME: This is only exposed because we need to use it in `analyse.rs`
|
||||
// which is not yet uplifted. Once that's done, we should remove this.
|
||||
@ -139,7 +159,7 @@ pub trait SolverDelegateEvalExt: SolverDelegate {
|
||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (
|
||||
Result<(NestedNormalizationGoals<Self::Interner>, bool, Certainty), NoSolution>,
|
||||
Result<(NestedNormalizationGoals<Self::Interner>, HasChanged, Certainty), NoSolution>,
|
||||
Option<inspect::GoalEvaluation<Self::Interner>>,
|
||||
);
|
||||
}
|
||||
@ -149,31 +169,41 @@ where
|
||||
D: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
/// Evaluates a goal from **outside** of the trait solver.
|
||||
///
|
||||
/// Using this while inside of the solver is wrong as it uses a new
|
||||
/// search graph which would break cycle detection.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) {
|
||||
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
|
||||
) -> (Result<(HasChanged, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) {
|
||||
EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, |ecx| {
|
||||
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
|
||||
})
|
||||
}
|
||||
|
||||
fn root_goal_may_hold_with_depth(
|
||||
&self,
|
||||
root_depth: usize,
|
||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||
) -> bool {
|
||||
self.probe(|| {
|
||||
EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, |ecx| {
|
||||
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
|
||||
})
|
||||
.0
|
||||
})
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn evaluate_root_goal_raw(
|
||||
&self,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (
|
||||
Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution>,
|
||||
Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution>,
|
||||
Option<inspect::GoalEvaluation<I>>,
|
||||
) {
|
||||
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
|
||||
EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, |ecx| {
|
||||
ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal)
|
||||
})
|
||||
}
|
||||
@ -197,10 +227,11 @@ where
|
||||
/// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]).
|
||||
pub(super) fn enter_root<R>(
|
||||
delegate: &D,
|
||||
root_depth: usize,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
|
||||
) -> (R, Option<inspect::GoalEvaluation<I>>) {
|
||||
let mut search_graph = SearchGraph::new(delegate.solver_mode());
|
||||
let mut search_graph = SearchGraph::new(delegate.solver_mode(), root_depth);
|
||||
|
||||
let mut ecx = EvalCtxt {
|
||||
delegate,
|
||||
@ -339,7 +370,7 @@ where
|
||||
goal_evaluation_kind: GoalEvaluationKind,
|
||||
source: GoalSource,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
) -> Result<(bool, Certainty), NoSolution> {
|
||||
) -> Result<(HasChanged, Certainty), NoSolution> {
|
||||
let (normalization_nested_goals, has_changed, certainty) =
|
||||
self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?;
|
||||
assert!(normalization_nested_goals.is_empty());
|
||||
@ -360,7 +391,7 @@ where
|
||||
goal_evaluation_kind: GoalEvaluationKind,
|
||||
_source: GoalSource,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
) -> Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution> {
|
||||
) -> Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution> {
|
||||
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
||||
let mut goal_evaluation =
|
||||
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
|
||||
@ -378,8 +409,13 @@ where
|
||||
Ok(response) => response,
|
||||
};
|
||||
|
||||
let has_changed = !response.value.var_values.is_identity_modulo_regions()
|
||||
|| !response.value.external_constraints.opaque_types.is_empty();
|
||||
let has_changed = if !response.value.var_values.is_identity_modulo_regions()
|
||||
|| !response.value.external_constraints.opaque_types.is_empty()
|
||||
{
|
||||
HasChanged::Yes
|
||||
} else {
|
||||
HasChanged::No
|
||||
};
|
||||
|
||||
let (normalization_nested_goals, certainty) =
|
||||
self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);
|
||||
@ -552,7 +588,7 @@ where
|
||||
for (source, goal) in goals.goals {
|
||||
let (has_changed, certainty) =
|
||||
self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?;
|
||||
if has_changed {
|
||||
if has_changed == HasChanged::Yes {
|
||||
unchanged_certainty = None;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,14 @@ enum GoalEvaluationKind {
|
||||
Nested,
|
||||
}
|
||||
|
||||
/// Whether evaluating this goal ended up changing the
|
||||
/// inference state.
|
||||
#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)]
|
||||
pub enum HasChanged {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
// FIXME(trait-system-refactor-initiative#117): we don't detect whether a response
|
||||
// ended up pulling down any universes.
|
||||
fn has_no_inference_or_external_constraints<I: Interner>(
|
||||
|
@ -40,9 +40,6 @@ where
|
||||
}
|
||||
|
||||
const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize = 4;
|
||||
fn recursion_limit(cx: I) -> usize {
|
||||
cx.recursion_limit()
|
||||
}
|
||||
|
||||
fn initial_provisional_result(
|
||||
cx: I,
|
||||
|
@ -6,6 +6,7 @@ pub mod inspect;
|
||||
mod normalize;
|
||||
mod select;
|
||||
|
||||
pub(crate) use delegate::SolverDelegate;
|
||||
pub use fulfill::{FulfillmentCtxt, NextSolverError};
|
||||
pub(crate) use normalize::deeply_normalize_for_diagnostics;
|
||||
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
|
||||
|
@ -12,7 +12,7 @@ use rustc_infer::traits::{
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
|
||||
use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::Certainty;
|
||||
@ -86,10 +86,7 @@ impl<'tcx> ObligationStorage<'tcx> {
|
||||
let result = <&SolverDelegate<'tcx>>::from(infcx)
|
||||
.evaluate_root_goal(goal, GenerateProofTree::No)
|
||||
.0;
|
||||
match result {
|
||||
Ok((has_changed, _)) => has_changed,
|
||||
_ => false,
|
||||
}
|
||||
matches!(result, Ok((HasChanged::Yes, _)))
|
||||
}));
|
||||
})
|
||||
}
|
||||
@ -113,7 +110,7 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> {
|
||||
&self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
result: &Result<(bool, Certainty), NoSolution>,
|
||||
result: &Result<(HasChanged, Certainty), NoSolution>,
|
||||
) {
|
||||
if let Some(inspector) = infcx.obligation_inspector.get() {
|
||||
let result = match result {
|
||||
@ -181,7 +178,11 @@ where
|
||||
continue;
|
||||
}
|
||||
};
|
||||
has_changed |= changed;
|
||||
|
||||
if changed == HasChanged::Yes {
|
||||
has_changed = true;
|
||||
}
|
||||
|
||||
match certainty {
|
||||
Certainty::Yes => {}
|
||||
Certainty::Maybe(_) => self.obligations.register(obligation),
|
||||
|
@ -19,6 +19,7 @@ use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
pub use rustc_next_trait_solver::coherence::*;
|
||||
use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument, warn};
|
||||
@ -28,7 +29,7 @@ use crate::error_reporting::traits::suggest_new_overflow_limit;
|
||||
use crate::infer::InferOk;
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
|
||||
use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::select::IntercrateAmbiguityCause;
|
||||
use crate::traits::{
|
||||
@ -333,6 +334,16 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
|
||||
let infcx = selcx.infcx;
|
||||
|
||||
if infcx.next_trait_solver() {
|
||||
// A fast path optimization, try evaluating all goals with
|
||||
// a very low recursion depth and bail if any of them don't
|
||||
// hold.
|
||||
if !obligations.iter().all(|o| {
|
||||
<&SolverDelegate<'tcx>>::from(infcx)
|
||||
.root_goal_may_hold_with_depth(8, Goal::new(infcx.tcx, o.param_env, o.predicate))
|
||||
}) {
|
||||
return IntersectionHasImpossibleObligations::Yes;
|
||||
}
|
||||
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
|
||||
ocx.register_obligations(obligations.iter().cloned());
|
||||
let errors_and_ambiguities = ocx.select_all_or_error();
|
||||
|
@ -81,7 +81,6 @@ pub trait Delegate {
|
||||
fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool;
|
||||
|
||||
const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize;
|
||||
fn recursion_limit(cx: Self::Cx) -> usize;
|
||||
|
||||
fn initial_provisional_result(
|
||||
cx: Self::Cx,
|
||||
@ -156,7 +155,7 @@ impl AvailableDepth {
|
||||
/// the remaining depth of all nested goals to prevent hangs
|
||||
/// in case there is exponential blowup.
|
||||
fn allowed_depth_for_nested<D: Delegate>(
|
||||
cx: D::Cx,
|
||||
root_depth: AvailableDepth,
|
||||
stack: &IndexVec<StackDepth, StackEntry<D::Cx>>,
|
||||
) -> Option<AvailableDepth> {
|
||||
if let Some(last) = stack.raw.last() {
|
||||
@ -170,7 +169,7 @@ impl AvailableDepth {
|
||||
AvailableDepth(last.available_depth.0 - 1)
|
||||
})
|
||||
} else {
|
||||
Some(AvailableDepth(D::recursion_limit(cx)))
|
||||
Some(root_depth)
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,6 +359,7 @@ struct ProvisionalCacheEntry<X: Cx> {
|
||||
|
||||
pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
|
||||
mode: SolverMode,
|
||||
root_depth: AvailableDepth,
|
||||
/// The stack of goals currently being computed.
|
||||
///
|
||||
/// An element is *deeper* in the stack if its index is *lower*.
|
||||
@ -374,9 +374,10 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
|
||||
}
|
||||
|
||||
impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||
pub fn new(mode: SolverMode) -> SearchGraph<D> {
|
||||
pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph<D> {
|
||||
Self {
|
||||
mode,
|
||||
root_depth: AvailableDepth(root_depth),
|
||||
stack: Default::default(),
|
||||
provisional_cache: Default::default(),
|
||||
_marker: PhantomData,
|
||||
@ -460,7 +461,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||
inspect: &mut D::ProofTreeBuilder,
|
||||
mut evaluate_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result,
|
||||
) -> X::Result {
|
||||
let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::<D>(cx, &self.stack)
|
||||
let Some(available_depth) =
|
||||
AvailableDepth::allowed_depth_for_nested::<D>(self.root_depth, &self.stack)
|
||||
else {
|
||||
return self.handle_overflow(cx, input, inspect);
|
||||
};
|
||||
|
@ -1,11 +0,0 @@
|
||||
//@ known-bug: rust-lang/rust#124894
|
||||
//@ compile-flags: -Znext-solver=coherence
|
||||
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
pub trait IsTrue<const mem: bool> {}
|
||||
impl<T> IsZST for T where (): IsTrue<{ std::mem::size_of::<T>() == 0 }> {}
|
||||
|
||||
pub trait IsZST {}
|
||||
|
||||
impl IsZST for IsZST {}
|
@ -4,7 +4,7 @@ error[E0010]: allocations are not allowed in constants
|
||||
LL | const CON: Vec<i32> = vec![1, 2, 3];
|
||||
| ^^^^^^^^^^^^^ allocation not allowed in constants
|
||||
|
|
||||
= note: The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time.
|
||||
= note: The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created.
|
||||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0015]: cannot call non-const fn `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constants
|
||||
|
32
tests/ui/traits/next-solver/typeck/guide-ctors.rs
Normal file
32
tests/ui/traits/next-solver/typeck/guide-ctors.rs
Normal file
@ -0,0 +1,32 @@
|
||||
//@ compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
|
||||
// Makes sure we structurally normalize before trying to use expectation to guide
|
||||
// coercion in adt and tuples.
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
trait Coerce {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
struct TupleGuidance;
|
||||
impl Coerce for TupleGuidance {
|
||||
type Assoc = (&'static dyn Any,);
|
||||
}
|
||||
|
||||
struct AdtGuidance;
|
||||
impl Coerce for AdtGuidance {
|
||||
type Assoc = Adt<&'static dyn Any>;
|
||||
}
|
||||
|
||||
struct Adt<T> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
fn foo<'a, T: Coerce>(_: T::Assoc) {}
|
||||
|
||||
fn main() {
|
||||
foo::<TupleGuidance>((&0u32,));
|
||||
foo::<AdtGuidance>(Adt { f: &0u32 });
|
||||
}
|
@ -923,7 +923,6 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
|
||||
users_on_vacation = [
|
||||
"BoxyUwU",
|
||||
"fmease",
|
||||
"jhpratt",
|
||||
"jyn514",
|
||||
"oli-obk",
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user