mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-17 22:46:50 +00:00
change definitely non-productive cycles to error
This commit is contained in:
parent
ac951d3799
commit
01795b14f0
@ -271,12 +271,39 @@ where
|
||||
/// and will need to clearly document it in the rustc-dev-guide before
|
||||
/// stabilization.
|
||||
pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
|
||||
match (self.current_goal_kind, source) {
|
||||
(_, GoalSource::NormalizeGoal(step_kind)) => step_kind,
|
||||
(CurrentGoalKind::CoinductiveTrait, GoalSource::ImplWhereBound) => {
|
||||
PathKind::Coinductive
|
||||
match source {
|
||||
// We treat these goals as unknown for now. It is likely that most miscellaneous
|
||||
// nested goals will be converted to an inductive variant in the future.
|
||||
//
|
||||
// Having unknown cycles is always the safer option, as changing that to either
|
||||
// succeed or hard error is backwards compatible. If we incorrectly treat a cycle
|
||||
// as inductive even though it should not be, it may be unsound during coherence and
|
||||
// fixing it may cause inference breakage or introduce ambiguity.
|
||||
GoalSource::Misc => PathKind::Unknown,
|
||||
GoalSource::NormalizeGoal(path_kind) => path_kind,
|
||||
GoalSource::ImplWhereBound => {
|
||||
// We currently only consider a cycle coinductive if it steps
|
||||
// into a where-clause of a coinductive trait.
|
||||
//
|
||||
// We probably want to make all traits coinductive in the future,
|
||||
// so we treat cycles involving their where-clauses as ambiguous.
|
||||
if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind {
|
||||
PathKind::Coinductive
|
||||
} else {
|
||||
PathKind::Unknown
|
||||
}
|
||||
}
|
||||
_ => PathKind::Inductive,
|
||||
// Relating types is always unproductive. If we were to map proof trees to
|
||||
// corecursive functions as explained in #136824, relating types never
|
||||
// introduces a constructor which could cause the recursion to be guarded.
|
||||
GoalSource::TypeRelating => PathKind::Inductive,
|
||||
// Instantiating a higher ranked goal can never cause the recursion to be
|
||||
// guarded and is therefore unproductive.
|
||||
GoalSource::InstantiateHigherRanked => PathKind::Inductive,
|
||||
// These goal sources are likely unproductive and can be changed to
|
||||
// `PathKind::Inductive`. Keeping them as unknown until we're confident
|
||||
// about this and have an example where it is necessary.
|
||||
GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
@ -606,7 +633,7 @@ where
|
||||
|
||||
let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw(
|
||||
GoalEvaluationKind::Nested,
|
||||
GoalSource::Misc,
|
||||
GoalSource::TypeRelating,
|
||||
unconstrained_goal,
|
||||
)?;
|
||||
// Add the nested goals from normalization to our own nested goals.
|
||||
@ -683,7 +710,7 @@ where
|
||||
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
|
||||
goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(
|
||||
self,
|
||||
GoalSource::Misc,
|
||||
GoalSource::TypeRelating,
|
||||
goal.param_env,
|
||||
));
|
||||
self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
|
||||
@ -939,7 +966,15 @@ where
|
||||
rhs: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
|
||||
self.add_goals(GoalSource::Misc, goals);
|
||||
if cfg!(debug_assertions) {
|
||||
for g in goals.iter() {
|
||||
match g.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {}
|
||||
p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
self.add_goals(GoalSource::TypeRelating, goals);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -421,7 +421,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
|
||||
self.add_goal(
|
||||
delegate,
|
||||
max_input_universe,
|
||||
GoalSource::Misc,
|
||||
GoalSource::TypeRelating,
|
||||
goal.with(delegate.cx(), goal.predicate),
|
||||
);
|
||||
}
|
||||
|
@ -313,7 +313,9 @@ where
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
);
|
||||
self.add_goal(GoalSource::Misc, alias_relate_goal);
|
||||
// We normalize the self type to be able to relate it with
|
||||
// types from candidates.
|
||||
self.add_goal(GoalSource::TypeRelating, alias_relate_goal);
|
||||
self.try_evaluate_added_goals()?;
|
||||
Ok(self.resolve_vars_if_possible(normalized_term))
|
||||
} else {
|
||||
|
@ -24,7 +24,8 @@ where
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
);
|
||||
self.add_goal(GoalSource::Misc, goal);
|
||||
// A projection goal holds if the alias is equal to the expected term.
|
||||
self.add_goal(GoalSource::TypeRelating, goal);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
||||
|
||||
use rustc_type_ir::Interner;
|
||||
use rustc_type_ir::search_graph::{self, PathKind};
|
||||
use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult};
|
||||
use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult};
|
||||
|
||||
use super::inspect::ProofTreeBuilder;
|
||||
use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints};
|
||||
@ -47,7 +47,8 @@ where
|
||||
) -> QueryResult<I> {
|
||||
match kind {
|
||||
PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes),
|
||||
PathKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)),
|
||||
PathKind::Unknown => response_no_constraints(cx, input, Certainty::overflow(false)),
|
||||
PathKind::Inductive => Err(NoSolution),
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,12 +58,7 @@ where
|
||||
input: CanonicalInput<I>,
|
||||
result: QueryResult<I>,
|
||||
) -> bool {
|
||||
match kind {
|
||||
PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes) == result,
|
||||
PathKind::Inductive => {
|
||||
response_no_constraints(cx, input, Certainty::overflow(false)) == result
|
||||
}
|
||||
}
|
||||
Self::initial_provisional_result(cx, kind, input) == result
|
||||
}
|
||||
|
||||
fn on_stack_overflow(
|
||||
|
@ -440,7 +440,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
|
||||
match (child_mode, nested_goal.source()) {
|
||||
(
|
||||
ChildMode::Trait(_) | ChildMode::Host(_),
|
||||
GoalSource::Misc | GoalSource::NormalizeGoal(_),
|
||||
GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
|
||||
) => {
|
||||
continue;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
/// behavior as long as the resulting behavior is still correct.
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
@ -20,7 +21,7 @@ use std::marker::PhantomData;
|
||||
use derive_where::derive_where;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::HashStable_NoContext;
|
||||
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::data_structures::HashMap;
|
||||
@ -111,21 +112,32 @@ pub trait Delegate {
|
||||
/// In the initial iteration of a cycle, we do not yet have a provisional
|
||||
/// result. In the case we return an initial provisional result depending
|
||||
/// on the kind of cycle.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||
pub enum PathKind {
|
||||
Coinductive,
|
||||
/// A path consisting of only inductive/unproductive steps.
|
||||
Inductive,
|
||||
/// A path which is not be coinductive right now but we may want
|
||||
/// to change of them to be so in the future. We return an ambiguous
|
||||
/// result in this case to prevent people from relying on this.
|
||||
Unknown,
|
||||
/// A path with at least one coinductive step. Such cycles hold.
|
||||
Coinductive,
|
||||
}
|
||||
|
||||
impl PathKind {
|
||||
/// Returns the path kind when merging `self` with `rest`.
|
||||
///
|
||||
/// Given an inductive path `self` and a coinductive path `rest`,
|
||||
/// the path `self -> rest` would be coinductive.
|
||||
///
|
||||
/// This operation represents an ordering and would be equivalent
|
||||
/// to `max(self, rest)`.
|
||||
fn extend(self, rest: PathKind) -> PathKind {
|
||||
match self {
|
||||
PathKind::Coinductive => PathKind::Coinductive,
|
||||
PathKind::Inductive => rest,
|
||||
match (self, rest) {
|
||||
(PathKind::Coinductive, _) | (_, PathKind::Coinductive) => PathKind::Coinductive,
|
||||
(PathKind::Unknown, _) | (_, PathKind::Unknown) => PathKind::Unknown,
|
||||
(PathKind::Inductive, PathKind::Inductive) => PathKind::Inductive,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -159,9 +171,6 @@ impl UsageKind {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn and_merge(&mut self, other: impl Into<Self>) {
|
||||
*self = self.merge(other);
|
||||
}
|
||||
}
|
||||
|
||||
/// For each goal we track whether the paths from this goal
|
||||
@ -297,7 +306,7 @@ impl CycleHeads {
|
||||
|
||||
let path_from_entry = match step_kind {
|
||||
PathKind::Coinductive => AllPathsToHeadCoinductive::Yes,
|
||||
PathKind::Inductive => path_from_entry,
|
||||
PathKind::Unknown | PathKind::Inductive => path_from_entry,
|
||||
};
|
||||
|
||||
self.insert(head, path_from_entry);
|
||||
@ -305,6 +314,63 @@ impl CycleHeads {
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// Tracks how nested goals have been accessed. This is necessary to disable
|
||||
/// global cache entries if computing them would otherwise result in a cycle or
|
||||
/// access a provisional cache entry.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PathsToNested: u8 {
|
||||
/// The initial value when adding a goal to its own nested goals.
|
||||
const EMPTY = 1 << 0;
|
||||
const INDUCTIVE = 1 << 1;
|
||||
const UNKNOWN = 1 << 2;
|
||||
const COINDUCTIVE = 1 << 3;
|
||||
}
|
||||
}
|
||||
impl From<PathKind> for PathsToNested {
|
||||
fn from(path: PathKind) -> PathsToNested {
|
||||
match path {
|
||||
PathKind::Inductive => PathsToNested::INDUCTIVE,
|
||||
PathKind::Unknown => PathsToNested::UNKNOWN,
|
||||
PathKind::Coinductive => PathsToNested::COINDUCTIVE,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PathsToNested {
|
||||
/// The implementation of this function is kind of ugly. We check whether
|
||||
/// there currently exist 'weaker' paths in the set, if so we upgrade these
|
||||
/// paths to at least `path`.
|
||||
#[must_use]
|
||||
fn extend_with(mut self, path: PathKind) -> Self {
|
||||
match path {
|
||||
PathKind::Inductive => {
|
||||
if self.intersects(PathsToNested::EMPTY) {
|
||||
self.remove(PathsToNested::EMPTY);
|
||||
self.insert(PathsToNested::INDUCTIVE);
|
||||
}
|
||||
}
|
||||
PathKind::Unknown => {
|
||||
if self.intersects(PathsToNested::EMPTY | PathsToNested::INDUCTIVE) {
|
||||
self.remove(PathsToNested::EMPTY | PathsToNested::INDUCTIVE);
|
||||
self.insert(PathsToNested::UNKNOWN);
|
||||
}
|
||||
}
|
||||
PathKind::Coinductive => {
|
||||
if self.intersects(
|
||||
PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN,
|
||||
) {
|
||||
self.remove(
|
||||
PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN,
|
||||
);
|
||||
self.insert(PathsToNested::COINDUCTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// The nested goals of each stack entry and the path from the
|
||||
/// stack entry to that nested goal.
|
||||
///
|
||||
@ -322,15 +388,18 @@ impl CycleHeads {
|
||||
/// results from a the cycle BAB depending on the cycle root.
|
||||
#[derive_where(Debug, Default, Clone; X: Cx)]
|
||||
struct NestedGoals<X: Cx> {
|
||||
nested_goals: HashMap<X::Input, UsageKind>,
|
||||
nested_goals: HashMap<X::Input, PathsToNested>,
|
||||
}
|
||||
impl<X: Cx> NestedGoals<X> {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.nested_goals.is_empty()
|
||||
}
|
||||
|
||||
fn insert(&mut self, input: X::Input, path_from_entry: UsageKind) {
|
||||
self.nested_goals.entry(input).or_insert(path_from_entry).and_merge(path_from_entry);
|
||||
fn insert(&mut self, input: X::Input, paths_to_nested: PathsToNested) {
|
||||
match self.nested_goals.entry(input) {
|
||||
Entry::Occupied(mut entry) => *entry.get_mut() |= paths_to_nested,
|
||||
Entry::Vacant(entry) => drop(entry.insert(paths_to_nested)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the nested goals of a nested goal, given that the path `step_kind` from this goal
|
||||
@ -341,18 +410,15 @@ impl<X: Cx> NestedGoals<X> {
|
||||
/// the same as for the child.
|
||||
fn extend_from_child(&mut self, step_kind: PathKind, nested_goals: &NestedGoals<X>) {
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for (input, path_from_entry) in nested_goals.iter() {
|
||||
let path_from_entry = match step_kind {
|
||||
PathKind::Coinductive => UsageKind::Single(PathKind::Coinductive),
|
||||
PathKind::Inductive => path_from_entry,
|
||||
};
|
||||
self.insert(input, path_from_entry);
|
||||
for (input, paths_to_nested) in nested_goals.iter() {
|
||||
let paths_to_nested = paths_to_nested.extend_with(step_kind);
|
||||
self.insert(input, paths_to_nested);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "nightly", rustc_lint_query_instability)]
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
fn iter(&self) -> impl Iterator<Item = (X::Input, UsageKind)> {
|
||||
fn iter(&self) -> impl Iterator<Item = (X::Input, PathsToNested)> + '_ {
|
||||
self.nested_goals.iter().map(|(i, p)| (*i, *p))
|
||||
}
|
||||
|
||||
@ -490,7 +556,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||
// goals as this change may cause them to now depend on additional
|
||||
// goals, resulting in new cycles. See the dev-guide for examples.
|
||||
if parent_depends_on_cycle {
|
||||
parent.nested_goals.insert(parent.input, UsageKind::Single(PathKind::Inductive))
|
||||
parent.nested_goals.insert(parent.input, PathsToNested::EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -666,7 +732,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||
//
|
||||
// We must therefore not use the global cache entry for `B` in that case.
|
||||
// See tests/ui/traits/next-solver/cycles/hidden-by-overflow.rs
|
||||
last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Inductive));
|
||||
last.nested_goals.insert(last.input, PathsToNested::EMPTY);
|
||||
}
|
||||
|
||||
debug!("encountered stack overflow");
|
||||
@ -749,16 +815,11 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||
|
||||
// We now care about the path from the next highest cycle head to the
|
||||
// provisional cache entry.
|
||||
match path_from_head {
|
||||
PathKind::Coinductive => {}
|
||||
PathKind::Inductive => {
|
||||
*path_from_head = Self::cycle_path_kind(
|
||||
&self.stack,
|
||||
stack_entry.step_kind_from_parent,
|
||||
head,
|
||||
)
|
||||
}
|
||||
}
|
||||
*path_from_head = path_from_head.extend(Self::cycle_path_kind(
|
||||
&self.stack,
|
||||
stack_entry.step_kind_from_parent,
|
||||
head,
|
||||
));
|
||||
// Mutate the result of the provisional cache entry in case we did
|
||||
// not reach a fixpoint.
|
||||
*result = mutate_result(input, *result);
|
||||
@ -858,7 +919,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||
for &ProvisionalCacheEntry {
|
||||
encountered_overflow,
|
||||
ref heads,
|
||||
path_from_head,
|
||||
path_from_head: head_to_provisional,
|
||||
result: _,
|
||||
} in entries.iter()
|
||||
{
|
||||
@ -870,24 +931,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||
|
||||
// A provisional cache entry only applies if the path from its highest head
|
||||
// matches the path when encountering the goal.
|
||||
//
|
||||
// We check if any of the paths taken while computing the global goal
|
||||
// would end up with an applicable provisional cache entry.
|
||||
let head = heads.highest_cycle_head();
|
||||
let full_path = match Self::cycle_path_kind(stack, step_kind_from_parent, head) {
|
||||
PathKind::Coinductive => UsageKind::Single(PathKind::Coinductive),
|
||||
PathKind::Inductive => path_from_global_entry,
|
||||
};
|
||||
|
||||
match (full_path, path_from_head) {
|
||||
(UsageKind::Mixed, _)
|
||||
| (UsageKind::Single(PathKind::Coinductive), PathKind::Coinductive)
|
||||
| (UsageKind::Single(PathKind::Inductive), PathKind::Inductive) => {
|
||||
debug!(
|
||||
?full_path,
|
||||
?path_from_head,
|
||||
"cache entry not applicable due to matching paths"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
_ => debug!(?full_path, ?path_from_head, "paths don't match"),
|
||||
let head_to_curr = Self::cycle_path_kind(stack, step_kind_from_parent, head);
|
||||
let full_paths = path_from_global_entry.extend_with(head_to_curr);
|
||||
if full_paths.contains(head_to_provisional.into()) {
|
||||
debug!(
|
||||
?full_paths,
|
||||
?head_to_provisional,
|
||||
"cache entry not applicable due to matching paths"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -986,8 +1042,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
||||
let last = &mut self.stack[last_index];
|
||||
last.reached_depth = last.reached_depth.max(next_index);
|
||||
|
||||
last.nested_goals.insert(input, UsageKind::Single(step_kind_from_parent));
|
||||
last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Inductive));
|
||||
last.nested_goals.insert(input, step_kind_from_parent.into());
|
||||
last.nested_goals.insert(last.input, PathsToNested::EMPTY);
|
||||
if last_index != head {
|
||||
last.heads.insert(head, step_kind_from_parent);
|
||||
}
|
||||
|
@ -58,20 +58,24 @@ impl<I: Interner, P> Goal<I, P> {
|
||||
/// Why a specific goal has to be proven.
|
||||
///
|
||||
/// This is necessary as we treat nested goals different depending on
|
||||
/// their source. This is currently mostly used by proof tree visitors
|
||||
/// but will be used by cycle handling in the future.
|
||||
/// their source. This is used to decide whether a cycle is coinductive.
|
||||
/// See the documentation of `EvalCtxt::step_kind_for_source` for more details
|
||||
/// about this.
|
||||
///
|
||||
/// It is also used by proof tree visitors, e.g. for diagnostics purposes.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
|
||||
pub enum GoalSource {
|
||||
Misc,
|
||||
/// We're proving a where-bound of an impl.
|
||||
/// A nested goal required to prove that types are equal/subtypes.
|
||||
/// This is always an unproductive step.
|
||||
///
|
||||
/// FIXME(-Znext-solver=coinductive): Explain how and why this
|
||||
/// changes whether cycles are coinductive.
|
||||
/// This is also used for all `NormalizesTo` goals as we they are used
|
||||
/// to relate types in `AliasRelate`.
|
||||
TypeRelating,
|
||||
/// We're proving a where-bound of an impl.
|
||||
ImplWhereBound,
|
||||
/// Const conditions that need to hold for `~const` alias bounds to hold.
|
||||
///
|
||||
/// FIXME(-Znext-solver=coinductive): Are these even coinductive?
|
||||
AliasBoundConstCondition,
|
||||
/// Instantiating a higher-ranked goal and re-proving it.
|
||||
InstantiateHigherRanked,
|
||||
@ -79,7 +83,6 @@ pub enum GoalSource {
|
||||
/// This is used in two places: projecting to an opaque whose hidden type
|
||||
/// is already registered in the opaque type storage, and for rigid projections.
|
||||
AliasWellFormed,
|
||||
|
||||
/// In case normalizing aliases in nested goals cycles, eagerly normalizing these
|
||||
/// aliases in the context of the parent may incorrectly change the cycle kind.
|
||||
/// Normalizing aliases in goals therefore tracks the original path kind for this
|
||||
|
@ -1,4 +1,7 @@
|
||||
//@ check-pass
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
|
||||
trait A<'a> {}
|
||||
trait B<'b> {}
|
||||
|
@ -1,4 +1,7 @@
|
||||
//@ check-pass
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
|
||||
// Make sure that we don't look into associated type bounds when looking for
|
||||
// supertraits that define an associated type. Fixes #76593.
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0275]: overflow evaluating the requirement `Loop == _`
|
||||
error[E0271]: type mismatch resolving `Loop normalizes-to _`
|
||||
--> $DIR/inherent-impls-overflow.rs:10:6
|
||||
|
|
||||
LL | impl Loop {}
|
||||
| ^^^^
|
||||
| ^^^^ types differ
|
||||
|
||||
error: type parameter `T` is only used recursively
|
||||
--> $DIR/inherent-impls-overflow.rs:14:24
|
||||
@ -36,4 +36,5 @@ LL | impl Poly0<()> {}
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
||||
Some errors have detailed explanations: E0271, E0275.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
|
@ -9,7 +9,7 @@ type Loop = Loop; //[current]~ ERROR overflow normalizing the type alias `Loop`
|
||||
|
||||
impl Loop {}
|
||||
//[current]~^ ERROR overflow normalizing the type alias `Loop`
|
||||
//[next]~^^ ERROR overflow evaluating the requirement `Loop == _`
|
||||
//[next]~^^ ERROR type mismatch resolving `Loop normalizes-to _`
|
||||
|
||||
type Poly0<T> = Poly1<(T,)>;
|
||||
//[current]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>`
|
||||
|
@ -6,9 +6,11 @@
|
||||
trait Overflow {
|
||||
type Assoc;
|
||||
}
|
||||
impl<T> Overflow for T {
|
||||
type Assoc = <T as Overflow>::Assoc;
|
||||
//~^ ERROR: overflow
|
||||
impl<T> Overflow for T
|
||||
where
|
||||
(T,): Overflow
|
||||
{
|
||||
type Assoc = <(T,) as Overflow>::Assoc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,19 +1,15 @@
|
||||
error[E0275]: overflow evaluating the requirement `<T as Overflow>::Assoc == _`
|
||||
--> $DIR/trait_ref_is_knowable-norm-overflow.rs:10:18
|
||||
|
|
||||
LL | type Assoc = <T as Overflow>::Assoc;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0119]: conflicting implementations of trait `Trait`
|
||||
--> $DIR/trait_ref_is_knowable-norm-overflow.rs:18:1
|
||||
--> $DIR/trait_ref_is_knowable-norm-overflow.rs:20:1
|
||||
|
|
||||
LL | impl<T: Copy> Trait for T {}
|
||||
| ------------------------- first implementation here
|
||||
LL | struct LocalTy;
|
||||
LL | impl Trait for <LocalTy as Overflow>::Assoc {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
|
||||
|
|
||||
= note: overflow evaluating the requirement `_ == <LocalTy as Overflow>::Assoc`
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`trait_ref_is_knowable_norm_overflow`)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Some errors have detailed explanations: E0119, E0275.
|
||||
For more information about an error, try `rustc --explain E0119`.
|
||||
For more information about this error, try `rustc --explain E0119`.
|
||||
|
@ -0,0 +1,21 @@
|
||||
// Regression test for trait-system-refactor-initiative#114.
|
||||
//
|
||||
// We previously treated the cycle when trying to use the
|
||||
// `<R as DimMin<C>>::Output: DimMin` where-bound when
|
||||
// normalizing `<R as DimMin<C>>::Output` as ambiguous, causing
|
||||
// this to error.
|
||||
|
||||
//@ check-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
//@ ignore-compare-mode-next-solver
|
||||
|
||||
pub trait DimMin<D> {
|
||||
type Output;
|
||||
}
|
||||
pub fn repro<R: DimMin<C>, C>()
|
||||
where
|
||||
<R as DimMin<C>>::Output: DimMin<C, Output = <R as DimMin<C>>::Output>,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -13,12 +13,7 @@ fn needs_bar<S: Bar>() {}
|
||||
|
||||
fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() {
|
||||
needs_bar::<T::Assoc1>();
|
||||
//~^ ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Sized`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar`
|
||||
//~^ ERROR the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,59 +1,19 @@
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
|
||||
error[E0277]: the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
|
||||
--> $DIR/recursive-self-normalization-2.rs:15:17
|
||||
|
|
||||
LL | needs_bar::<T::Assoc1>();
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar`
|
||||
--> $DIR/recursive-self-normalization-2.rs:15:17
|
||||
|
|
||||
LL | needs_bar::<T::Assoc1>();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo1>::Assoc1`
|
||||
|
|
||||
note: required by a bound in `needs_bar`
|
||||
--> $DIR/recursive-self-normalization-2.rs:12:17
|
||||
|
|
||||
LL | fn needs_bar<S: Bar>() {}
|
||||
| ^^^ required by this bound in `needs_bar`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo1>::Assoc1: Bar {
|
||||
| ++++++++++++++++++++++++++++++
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Sized`
|
||||
--> $DIR/recursive-self-normalization-2.rs:15:17
|
||||
|
|
||||
LL | needs_bar::<T::Assoc1>();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: required by an implicit `Sized` bound in `needs_bar`
|
||||
--> $DIR/recursive-self-normalization-2.rs:12:14
|
||||
|
|
||||
LL | fn needs_bar<S: Bar>() {}
|
||||
| ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar`
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | fn needs_bar<S: Bar + ?Sized>() {}
|
||||
| ++++++++
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
|
||||
--> $DIR/recursive-self-normalization-2.rs:15:5
|
||||
|
|
||||
LL | needs_bar::<T::Assoc1>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
|
||||
--> $DIR/recursive-self-normalization-2.rs:15:5
|
||||
|
|
||||
LL | needs_bar::<T::Assoc1>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
|
||||
--> $DIR/recursive-self-normalization-2.rs:15:17
|
||||
|
|
||||
LL | needs_bar::<T::Assoc1>();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -9,12 +9,7 @@ fn needs_bar<S: Bar>() {}
|
||||
|
||||
fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() {
|
||||
needs_bar::<T::Assoc>();
|
||||
//~^ ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Sized`
|
||||
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Bar`
|
||||
//~^ ERROR the trait bound `<T as Foo>::Assoc: Bar` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,59 +1,19 @@
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
|
||||
error[E0277]: the trait bound `<T as Foo>::Assoc: Bar` is not satisfied
|
||||
--> $DIR/recursive-self-normalization.rs:11:17
|
||||
|
|
||||
LL | needs_bar::<T::Assoc>();
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Bar`
|
||||
--> $DIR/recursive-self-normalization.rs:11:17
|
||||
|
|
||||
LL | needs_bar::<T::Assoc>();
|
||||
| ^^^^^^^^
|
||||
| ^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo>::Assoc`
|
||||
|
|
||||
note: required by a bound in `needs_bar`
|
||||
--> $DIR/recursive-self-normalization.rs:8:17
|
||||
|
|
||||
LL | fn needs_bar<S: Bar>() {}
|
||||
| ^^^ required by this bound in `needs_bar`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() where <T as Foo>::Assoc: Bar {
|
||||
| ++++++++++++++++++++++++++++
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Sized`
|
||||
--> $DIR/recursive-self-normalization.rs:11:17
|
||||
|
|
||||
LL | needs_bar::<T::Assoc>();
|
||||
| ^^^^^^^^
|
||||
|
|
||||
note: required by an implicit `Sized` bound in `needs_bar`
|
||||
--> $DIR/recursive-self-normalization.rs:8:14
|
||||
|
|
||||
LL | fn needs_bar<S: Bar>() {}
|
||||
| ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar`
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | fn needs_bar<S: Bar + ?Sized>() {}
|
||||
| ++++++++
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
|
||||
--> $DIR/recursive-self-normalization.rs:11:5
|
||||
|
|
||||
LL | needs_bar::<T::Assoc>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
|
||||
--> $DIR/recursive-self-normalization.rs:11:5
|
||||
|
|
||||
LL | needs_bar::<T::Assoc>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
|
||||
--> $DIR/recursive-self-normalization.rs:11:17
|
||||
|
|
||||
LL | needs_bar::<T::Assoc>();
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
Loading…
Reference in New Issue
Block a user