mirror of
https://github.com/rust-lang/rust
synced 2024-11-05 20:45:15 +00:00
Rollup merge of #125343 - lcnr:eagerly-normalize-added-goals, r=compiler-errors
`-Znext-solver`: eagerly normalize when adding goals fixes #125269. I am not totally with this fix and going to keep this open until we have a more general discussion about how to handle hangs caused by lazy norm in the new solver.
This commit is contained in:
commit
fb95fda87f
12 changed files with 250 additions and 62 deletions
|
@ -121,17 +121,14 @@ pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool {
|
|||
#[inline]
|
||||
pub fn allow_normalization(self) -> bool {
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_)) => false,
|
||||
// `NormalizesTo` is only used in the new solver, so this shouldn't
|
||||
// matter. Normalizing `term` would be 'wrong' however, as it changes whether
|
||||
// `normalizes-to(<T as Trait>::Assoc, <T as Trait>::Assoc)` holds.
|
||||
PredicateKind::NormalizesTo(..) => false,
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_))
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::NormalizesTo(..) => false,
|
||||
PredicateKind::Clause(ClauseKind::Trait(_))
|
||||
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::Projection(_))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::ObjectSafe(_)
|
||||
| PredicateKind::Subtype(_)
|
||||
| PredicateKind::Coerce(_)
|
||||
|
|
|
@ -28,6 +28,7 @@ pub(super) fn compute_alias_relate_goal(
|
|||
) -> QueryResult<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
|
||||
debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some());
|
||||
|
||||
// Structurally normalize the lhs.
|
||||
let lhs = if let Some(alias) = lhs.to_alias_term() {
|
||||
|
|
|
@ -13,11 +13,14 @@
|
|||
inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
|
||||
};
|
||||
use rustc_middle::traits::specialization_graph;
|
||||
use rustc_middle::ty::AliasRelationDirection;
|
||||
use rustc_middle::ty::TypeFolder;
|
||||
use rustc_middle::ty::{
|
||||
self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_type_ir::fold::TypeSuperFoldable;
|
||||
use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
|
||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use std::ops::ControlFlow;
|
||||
|
@ -455,13 +458,23 @@ fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult
|
|||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(super) fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
|
||||
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
|
||||
goal.predicate = goal
|
||||
.predicate
|
||||
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
|
||||
self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal);
|
||||
self.nested_goals.normalizes_to_goals.push(goal);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
|
||||
pub(super) fn add_goal(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
mut goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) {
|
||||
goal.predicate = goal
|
||||
.predicate
|
||||
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
|
||||
self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal);
|
||||
self.nested_goals.goals.push((source, goal));
|
||||
}
|
||||
|
@ -1084,3 +1097,63 @@ pub(super) fn walk_vtable(
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Eagerly replace aliases with inference variables, emitting `AliasRelate`
|
||||
/// goals, used when adding goals to the `EvalCtxt`. We compute the
|
||||
/// `AliasRelate` goals before evaluating the actual goal to get all the
|
||||
/// constraints we can.
|
||||
///
|
||||
/// This is a performance optimization to more eagerly detect cycles during trait
|
||||
/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
|
||||
struct ReplaceAliasWithInfer<'me, 'a, 'tcx> {
|
||||
ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.ecx.tcx()
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *ty.kind() {
|
||||
ty::Alias(..) if !ty.has_escaping_bound_vars() => {
|
||||
let infer_ty = self.ecx.next_ty_infer();
|
||||
let normalizes_to = ty::PredicateKind::AliasRelate(
|
||||
ty.into(),
|
||||
infer_ty.into(),
|
||||
AliasRelationDirection::Equate,
|
||||
);
|
||||
self.ecx.add_goal(
|
||||
GoalSource::Misc,
|
||||
Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
);
|
||||
infer_ty
|
||||
}
|
||||
_ => ty.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
|
||||
let infer_ct = self.ecx.next_const_infer(ct.ty());
|
||||
let normalizes_to = ty::PredicateKind::AliasRelate(
|
||||
ct.into(),
|
||||
infer_ct.into(),
|
||||
AliasRelationDirection::Equate,
|
||||
);
|
||||
self.ecx.add_goal(
|
||||
GoalSource::Misc,
|
||||
Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
);
|
||||
infer_ct
|
||||
}
|
||||
_ => ct.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,10 +89,8 @@ fn constrain(
|
|||
pub struct InspectCandidate<'a, 'tcx> {
|
||||
goal: &'a InspectGoal<'a, 'tcx>,
|
||||
kind: inspect::ProbeKind<TyCtxt<'tcx>>,
|
||||
nested_goals:
|
||||
Vec<(GoalSource, inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>)>,
|
||||
steps: Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
|
||||
final_state: inspect::CanonicalState<TyCtxt<'tcx>, ()>,
|
||||
impl_args: Option<inspect::CanonicalState<TyCtxt<'tcx>, ty::GenericArgsRef<'tcx>>>,
|
||||
result: QueryResult<'tcx>,
|
||||
shallow_certainty: Certainty,
|
||||
}
|
||||
|
@ -148,7 +146,7 @@ pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>>
|
|||
#[instrument(
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals)
|
||||
fields(goal = ?self.goal.goal, steps = ?self.steps)
|
||||
)]
|
||||
pub fn instantiate_nested_goals_and_opt_impl_args(
|
||||
&self,
|
||||
|
@ -157,22 +155,34 @@ pub fn instantiate_nested_goals_and_opt_impl_args(
|
|||
let infcx = self.goal.infcx;
|
||||
let param_env = self.goal.goal.param_env;
|
||||
let mut orig_values = self.goal.orig_values.to_vec();
|
||||
let instantiated_goals: Vec<_> = self
|
||||
.nested_goals
|
||||
.iter()
|
||||
.map(|(source, goal)| {
|
||||
(
|
||||
*source,
|
||||
|
||||
let mut instantiated_goals = vec![];
|
||||
let mut opt_impl_args = None;
|
||||
for step in &self.steps {
|
||||
match **step {
|
||||
inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
|
||||
source,
|
||||
canonical::instantiate_canonical_state(
|
||||
infcx,
|
||||
span,
|
||||
param_env,
|
||||
&mut orig_values,
|
||||
*goal,
|
||||
goal,
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
)),
|
||||
inspect::ProbeStep::RecordImplArgs { impl_args } => {
|
||||
opt_impl_args = Some(canonical::instantiate_canonical_state(
|
||||
infcx,
|
||||
span,
|
||||
param_env,
|
||||
&mut orig_values,
|
||||
impl_args,
|
||||
));
|
||||
}
|
||||
inspect::ProbeStep::MakeCanonicalResponse { .. }
|
||||
| inspect::ProbeStep::NestedProbe(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let () = canonical::instantiate_canonical_state(
|
||||
infcx,
|
||||
|
@ -182,17 +192,6 @@ pub fn instantiate_nested_goals_and_opt_impl_args(
|
|||
self.final_state,
|
||||
);
|
||||
|
||||
let impl_args = self.impl_args.map(|impl_args| {
|
||||
canonical::instantiate_canonical_state(
|
||||
infcx,
|
||||
span,
|
||||
param_env,
|
||||
&mut orig_values,
|
||||
impl_args,
|
||||
)
|
||||
.fold_with(&mut EagerResolver::new(infcx))
|
||||
});
|
||||
|
||||
if let Some(term_hack) = self.goal.normalizes_to_term_hack {
|
||||
// FIXME: We ignore the expected term of `NormalizesTo` goals
|
||||
// when computing the result of its candidates. This is
|
||||
|
@ -200,6 +199,9 @@ pub fn instantiate_nested_goals_and_opt_impl_args(
|
|||
let _ = term_hack.constrain(infcx, span, param_env);
|
||||
}
|
||||
|
||||
let opt_impl_args =
|
||||
opt_impl_args.map(|impl_args| impl_args.fold_with(&mut EagerResolver::new(infcx)));
|
||||
|
||||
let goals = instantiated_goals
|
||||
.into_iter()
|
||||
.map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
|
||||
|
@ -249,7 +251,7 @@ pub fn instantiate_nested_goals_and_opt_impl_args(
|
|||
})
|
||||
.collect();
|
||||
|
||||
(goals, impl_args)
|
||||
(goals, opt_impl_args)
|
||||
}
|
||||
|
||||
/// Visit all nested goals of this candidate, rolling back
|
||||
|
@ -279,17 +281,18 @@ pub fn source(&self) -> GoalSource {
|
|||
fn candidates_recur(
|
||||
&'a self,
|
||||
candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,
|
||||
nested_goals: &mut Vec<(
|
||||
GoalSource,
|
||||
inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
)>,
|
||||
probe: &inspect::Probe<TyCtxt<'tcx>>,
|
||||
steps: &mut Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
|
||||
probe: &'a inspect::Probe<TyCtxt<'tcx>>,
|
||||
) {
|
||||
let mut shallow_certainty = None;
|
||||
let mut impl_args = None;
|
||||
for step in &probe.steps {
|
||||
match *step {
|
||||
inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
|
||||
inspect::ProbeStep::AddGoal(..) | inspect::ProbeStep::RecordImplArgs { .. } => {
|
||||
steps.push(step)
|
||||
}
|
||||
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
|
||||
assert_eq!(shallow_certainty.replace(c), None);
|
||||
}
|
||||
inspect::ProbeStep::NestedProbe(ref probe) => {
|
||||
match probe.kind {
|
||||
// These never assemble candidates for the goal we're trying to solve.
|
||||
|
@ -305,18 +308,12 @@ fn candidates_recur(
|
|||
// Nested probes have to prove goals added in their parent
|
||||
// but do not leak them, so we truncate the added goals
|
||||
// afterwards.
|
||||
let num_goals = nested_goals.len();
|
||||
self.candidates_recur(candidates, nested_goals, probe);
|
||||
nested_goals.truncate(num_goals);
|
||||
let num_steps = steps.len();
|
||||
self.candidates_recur(candidates, steps, probe);
|
||||
steps.truncate(num_steps);
|
||||
}
|
||||
}
|
||||
}
|
||||
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
|
||||
assert_eq!(shallow_certainty.replace(c), None);
|
||||
}
|
||||
inspect::ProbeStep::RecordImplArgs { impl_args: i } => {
|
||||
assert_eq!(impl_args.replace(i), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,11 +335,10 @@ fn candidates_recur(
|
|||
candidates.push(InspectCandidate {
|
||||
goal: self,
|
||||
kind: probe.kind,
|
||||
nested_goals: nested_goals.clone(),
|
||||
steps: steps.clone(),
|
||||
final_state: probe.final_state,
|
||||
result,
|
||||
shallow_certainty,
|
||||
impl_args,
|
||||
result,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ LL | impl<T> Trait for Box<T> {}
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
|
||||
|
|
||||
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
|
||||
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<<std::boxed::Box<_> as WithAssoc<'a>>::Assoc>`
|
||||
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<_>`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ error[E0282]: type annotations needed
|
|||
--> $DIR/opaques.rs:13:20
|
||||
|
|
||||
LL | pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
|
||||
| ^ cannot infer type for associated type `<T as Trait<T>>::Assoc`
|
||||
| ^ cannot infer type
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -16,6 +16,22 @@ LL | where
|
|||
LL | T: AsExpression<Self::SqlType>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
|
||||
--> $DIR/as_expression.rs:57:15
|
||||
|
|
||||
LL | SelectInt.check("bar");
|
||||
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
|
||||
|
|
||||
= help: the trait `AsExpression<Text>` is implemented for `&str`
|
||||
= help: for that trait implementation, expected `Text`, found `Integer`
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
error[E0271]: type mismatch resolving `<&str as AsExpression<<SelectInt as Expression>::SqlType>>::Expression == _`
|
||||
--> $DIR/as_expression.rs:57:5
|
||||
|
|
||||
LL | SelectInt.check("bar");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ types differ
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0277.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
|
|
|
@ -55,6 +55,7 @@ impl<T> Foo for T where T: Expression {}
|
|||
|
||||
fn main() {
|
||||
SelectInt.check("bar");
|
||||
//[next]~^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
|
||||
//[current]~^^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
|
||||
//~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
|
||||
//[next]~| the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
|
||||
//[next]~| type mismatch
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated`
|
||||
error[E0284]: type annotations needed: cannot satisfy `{ || {} } == _`
|
||||
--> $DIR/const-region-infer-to-static-in-binder.rs:4:10
|
||||
|
|
||||
LL | struct X<const FN: fn() = { || {} }>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `{ || {} } == _`
|
||||
|
||||
error: using function pointers as const generic parameters is forbidden
|
||||
--> $DIR/const-region-infer-to-static-in-binder.rs:4:20
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
|
||||
// A regression test for #125269. We previously ended up
|
||||
// recursively proving `&<_ as SpeciesPackedElem>::Assoc: Typed`
|
||||
// for all aliases which ended up causing exponential blowup.
|
||||
//
|
||||
// This has been fixed by eagerly normalizing the associated
|
||||
// type before computing the nested goals, resulting in an
|
||||
// immediate inductive cycle.
|
||||
|
||||
pub trait Typed {}
|
||||
|
||||
pub struct SpeciesCases<E>(E);
|
||||
|
||||
pub trait SpeciesPackedElim {
|
||||
type Ogre;
|
||||
type Cyclops;
|
||||
type Wendigo;
|
||||
type Cavetroll;
|
||||
type Mountaintroll;
|
||||
type Swamptroll;
|
||||
type Dullahan;
|
||||
type Werewolf;
|
||||
type Occultsaurok;
|
||||
type Mightysaurok;
|
||||
type Slysaurok;
|
||||
type Mindflayer;
|
||||
type Minotaur;
|
||||
type Tidalwarrior;
|
||||
type Yeti;
|
||||
type Harvester;
|
||||
type Blueoni;
|
||||
type Redoni;
|
||||
type Cultistwarlord;
|
||||
type Cultistwarlock;
|
||||
type Huskbrute;
|
||||
type Tursus;
|
||||
type Gigasfrost;
|
||||
type AdletElder;
|
||||
type SeaBishop;
|
||||
type HaniwaGeneral;
|
||||
type TerracottaBesieger;
|
||||
type TerracottaDemolisher;
|
||||
type TerracottaPunisher;
|
||||
type TerracottaPursuer;
|
||||
type Cursekeeper;
|
||||
}
|
||||
|
||||
impl<'b, E: SpeciesPackedElim> Typed for &'b SpeciesCases<E>
|
||||
where
|
||||
&'b E::Ogre: Typed,
|
||||
&'b E::Cyclops: Typed,
|
||||
&'b E::Wendigo: Typed,
|
||||
&'b E::Cavetroll: Typed,
|
||||
&'b E::Mountaintroll: Typed,
|
||||
&'b E::Swamptroll: Typed,
|
||||
&'b E::Dullahan: Typed,
|
||||
&'b E::Werewolf: Typed,
|
||||
&'b E::Occultsaurok: Typed,
|
||||
&'b E::Mightysaurok: Typed,
|
||||
&'b E::Slysaurok: Typed,
|
||||
&'b E::Mindflayer: Typed,
|
||||
&'b E::Minotaur: Typed,
|
||||
&'b E::Tidalwarrior: Typed,
|
||||
&'b E::Yeti: Typed,
|
||||
&'b E::Harvester: Typed,
|
||||
&'b E::Blueoni: Typed,
|
||||
&'b E::Redoni: Typed,
|
||||
&'b E::Cultistwarlord: Typed,
|
||||
&'b E::Cultistwarlock: Typed,
|
||||
&'b E::Huskbrute: Typed,
|
||||
&'b E::Tursus: Typed,
|
||||
&'b E::Gigasfrost: Typed,
|
||||
&'b E::AdletElder: Typed,
|
||||
&'b E::SeaBishop: Typed,
|
||||
&'b E::HaniwaGeneral: Typed,
|
||||
&'b E::TerracottaBesieger: Typed,
|
||||
&'b E::TerracottaDemolisher: Typed,
|
||||
&'b E::TerracottaPunisher: Typed,
|
||||
&'b E::TerracottaPursuer: Typed,
|
||||
&'b E::Cursekeeper: Typed,
|
||||
{}
|
||||
|
||||
fn foo<T: Typed>() {}
|
||||
|
||||
fn main() {
|
||||
foo::<&_>();
|
||||
//~^ ERROR overflow evaluating the requirement `&_: Typed`
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
error[E0275]: overflow evaluating the requirement `&_: Typed`
|
||||
--> $DIR/cycle-modulo-ambig-aliases.rs:87:11
|
||||
|
|
||||
LL | foo::<&_>();
|
||||
| ^^
|
||||
|
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/cycle-modulo-ambig-aliases.rs:84:11
|
||||
|
|
||||
LL | fn foo<T: Typed>() {}
|
||||
| ^^^^^ required by this bound in `foo`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
|
@ -1,5 +1,5 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
//@ run-pass
|
||||
|
||||
// Test that selection prefers the builtin trait object impl for `Any`
|
||||
// instead of the user defined impl. Both impls apply to the trait
|
||||
|
|
Loading…
Reference in a new issue