mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Auto merge of #112383 - Dylan-DPC:rollup-et2z6nt, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #112076 (Fall back to bidirectional normalizes-to if no subst-relate candidate in alias-relate goal) - #112122 (Add `-Ztrait-solver=next-coherence`) - #112251 (rustdoc: convert `if let Some()` that always matches to variable) - #112345 (fix(expand): prevent infinity loop in macro containing only "///") - #112359 (Respect `RUST_BACKTRACE` for delayed bugs) - #112382 (download-rustc: Fix `x test core` on MacOS) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b2807b2bf3
@ -285,7 +285,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||||||
let infcx = self
|
let infcx = self
|
||||||
.tcx
|
.tcx
|
||||||
.infer_ctxt()
|
.infer_ctxt()
|
||||||
.with_opaque_type_inference(if self.tcx.trait_solver_next() {
|
.with_opaque_type_inference(if self.next_trait_solver() {
|
||||||
DefiningAnchor::Bind(def_id)
|
DefiningAnchor::Bind(def_id)
|
||||||
} else {
|
} else {
|
||||||
DefiningAnchor::Bubble
|
DefiningAnchor::Bubble
|
||||||
|
@ -188,7 +188,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||||||
|
|
||||||
// FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
|
// FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
|
||||||
// predefined opaques in the typeck root.
|
// predefined opaques in the typeck root.
|
||||||
if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
|
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
|
||||||
checker.register_predefined_opaques_in_new_solver();
|
checker.register_predefined_opaques_in_new_solver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,7 +383,7 @@ pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
|
|||||||
pub use diagnostic_impls::{
|
pub use diagnostic_impls::{
|
||||||
DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans,
|
DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans,
|
||||||
};
|
};
|
||||||
use std::backtrace::Backtrace;
|
use std::backtrace::{Backtrace, BacktraceStatus};
|
||||||
|
|
||||||
/// A handler deals with errors and other compiler output.
|
/// A handler deals with errors and other compiler output.
|
||||||
/// Certain errors (fatal, bug, unimpl) may cause immediate exit,
|
/// Certain errors (fatal, bug, unimpl) may cause immediate exit,
|
||||||
@ -1331,7 +1331,7 @@ impl HandlerInner {
|
|||||||
// once *any* errors were emitted (and truncate `delayed_span_bugs`
|
// once *any* errors were emitted (and truncate `delayed_span_bugs`
|
||||||
// when an error is first emitted, also), but maybe there's a case
|
// when an error is first emitted, also), but maybe there's a case
|
||||||
// in which that's not sound? otherwise this is really inefficient.
|
// in which that's not sound? otherwise this is really inefficient.
|
||||||
let backtrace = std::backtrace::Backtrace::force_capture();
|
let backtrace = std::backtrace::Backtrace::capture();
|
||||||
self.delayed_span_bugs
|
self.delayed_span_bugs
|
||||||
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
|
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
|
||||||
|
|
||||||
@ -1620,7 +1620,7 @@ impl HandlerInner {
|
|||||||
if self.flags.report_delayed_bugs {
|
if self.flags.report_delayed_bugs {
|
||||||
self.emit_diagnostic(&mut diagnostic);
|
self.emit_diagnostic(&mut diagnostic);
|
||||||
}
|
}
|
||||||
let backtrace = std::backtrace::Backtrace::force_capture();
|
let backtrace = std::backtrace::Backtrace::capture();
|
||||||
self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
|
self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1739,7 +1739,17 @@ impl DelayedDiagnostic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn decorate(mut self) -> Diagnostic {
|
fn decorate(mut self) -> Diagnostic {
|
||||||
|
match self.note.status() {
|
||||||
|
BacktraceStatus::Captured => {
|
||||||
self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note));
|
self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note));
|
||||||
|
}
|
||||||
|
// Avoid the needless newline when no backtrace has been captured,
|
||||||
|
// the display impl should just be a single line.
|
||||||
|
_ => {
|
||||||
|
self.inner.note(format!("delayed at {} - {}", self.inner.emitted_at, self.note));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,6 +249,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A single matcher position, representing the state of matching.
|
/// A single matcher position, representing the state of matching.
|
||||||
|
#[derive(Debug)]
|
||||||
struct MatcherPos {
|
struct MatcherPos {
|
||||||
/// The index into `TtParser::locs`, which represents the "dot".
|
/// The index into `TtParser::locs`, which represents the "dot".
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
@ -628,6 +628,40 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree)
|
|||||||
// after parsing/expansion. we can report every error in every macro this way.
|
// after parsing/expansion. we can report every error in every macro this way.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool {
|
||||||
|
if seq.separator.is_some() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
let mut is_empty = true;
|
||||||
|
let mut iter = seq.tts.iter().peekable();
|
||||||
|
while let Some(tt) = iter.next() {
|
||||||
|
match tt {
|
||||||
|
mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {}
|
||||||
|
mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => {
|
||||||
|
let mut now = t;
|
||||||
|
while let Some(&mbe::TokenTree::Token(
|
||||||
|
next @ Token { kind: DocComment(..), .. },
|
||||||
|
)) = iter.peek()
|
||||||
|
{
|
||||||
|
now = next;
|
||||||
|
iter.next();
|
||||||
|
}
|
||||||
|
let span = t.span.to(now.span);
|
||||||
|
sess.span_diagnostic.span_note_without_error(
|
||||||
|
span,
|
||||||
|
"doc comments are ignored in matcher position",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
mbe::TokenTree::Sequence(_, sub_seq)
|
||||||
|
if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|
||||||
|
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne) => {}
|
||||||
|
_ => is_empty = false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is_empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks that the lhs contains no repetition which could match an empty token
|
/// Checks that the lhs contains no repetition which could match an empty token
|
||||||
/// tree, because then the matcher would hang indefinitely.
|
/// tree, because then the matcher would hang indefinitely.
|
||||||
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
|
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
|
||||||
@ -644,16 +678,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenTree::Sequence(span, seq) => {
|
TokenTree::Sequence(span, seq) => {
|
||||||
if seq.separator.is_none()
|
if is_empty_token_tree(sess, seq) {
|
||||||
&& seq.tts.iter().all(|seq_tt| match seq_tt {
|
|
||||||
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
|
|
||||||
TokenTree::Sequence(_, sub_seq) => {
|
|
||||||
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|
|
||||||
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
{
|
|
||||||
let sp = span.entire();
|
let sp = span.entire();
|
||||||
sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
|
sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
|
||||||
return false;
|
return false;
|
||||||
|
@ -73,7 +73,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
|
|||||||
// NOTE: we may still need to normalize the built-in deref in case
|
// NOTE: we may still need to normalize the built-in deref in case
|
||||||
// we have some type like `&<Ty as Trait>::Assoc`, since users of
|
// we have some type like `&<Ty as Trait>::Assoc`, since users of
|
||||||
// autoderef expect this type to have been structurally normalized.
|
// autoderef expect this type to have been structurally normalized.
|
||||||
if self.infcx.tcx.trait_solver_next()
|
if self.infcx.next_trait_solver()
|
||||||
&& let ty::Alias(ty::Projection, _) = ty.kind()
|
&& let ty::Alias(ty::Projection, _) = ty.kind()
|
||||||
{
|
{
|
||||||
let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
|
let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
|
||||||
@ -161,8 +161,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
|
) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
|
||||||
let tcx = self.infcx.tcx;
|
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.infcx);
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx);
|
|
||||||
|
|
||||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||||
let normalized_ty = match self
|
let normalized_ty = match self
|
||||||
|
@ -1549,7 +1549,7 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||||||
.with_opaque_type_inference(DefiningAnchor::Bind(def_id))
|
.with_opaque_type_inference(DefiningAnchor::Bind(def_id))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
|
||||||
for (predicate, cause) in generator_interior_predicates {
|
for (predicate, cause) in generator_interior_predicates {
|
||||||
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
|
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
|
||||||
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
||||||
|
@ -156,7 +156,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||||||
// In the new solver, lazy norm may allow us to shallowly equate
|
// In the new solver, lazy norm may allow us to shallowly equate
|
||||||
// more types, but we emit possibly impossible-to-satisfy obligations.
|
// more types, but we emit possibly impossible-to-satisfy obligations.
|
||||||
// Filter these cases out to make sure our coercion is more accurate.
|
// Filter these cases out to make sure our coercion is more accurate.
|
||||||
if self.tcx.trait_solver_next() {
|
if self.next_trait_solver() {
|
||||||
if let Ok(res) = &res {
|
if let Ok(res) = &res {
|
||||||
for obligation in &res.obligations {
|
for obligation in &res.obligations {
|
||||||
if !self.predicate_may_hold(&obligation) {
|
if !self.predicate_may_hold(&obligation) {
|
||||||
|
@ -1476,7 +1476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
|
pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
let mut ty = self.resolve_vars_with_obligations(ty);
|
let mut ty = self.resolve_vars_with_obligations(ty);
|
||||||
|
|
||||||
if self.tcx.trait_solver_next()
|
if self.next_trait_solver()
|
||||||
&& let ty::Alias(ty::Projection, _) = ty.kind()
|
&& let ty::Alias(ty::Projection, _) = ty.kind()
|
||||||
{
|
{
|
||||||
match self
|
match self
|
||||||
|
@ -86,8 +86,8 @@ impl<'tcx> Inherited<'tcx> {
|
|||||||
|
|
||||||
Inherited {
|
Inherited {
|
||||||
typeck_results,
|
typeck_results,
|
||||||
|
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)),
|
||||||
infcx,
|
infcx,
|
||||||
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
|
|
||||||
locals: RefCell::new(Default::default()),
|
locals: RefCell::new(Default::default()),
|
||||||
deferred_sized_obligations: RefCell::new(Vec::new()),
|
deferred_sized_obligations: RefCell::new(Vec::new()),
|
||||||
deferred_call_resolutions: RefCell::new(Default::default()),
|
deferred_call_resolutions: RefCell::new(Default::default()),
|
||||||
|
@ -591,7 +591,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
.insert(opaque_type_key, hidden_type)
|
.insert(opaque_type_key, hidden_type)
|
||||||
&& last_opaque_ty.ty != hidden_type.ty
|
&& last_opaque_ty.ty != hidden_type.ty
|
||||||
{
|
{
|
||||||
assert!(!self.tcx().trait_solver_next());
|
assert!(!self.fcx.next_trait_solver());
|
||||||
hidden_type
|
hidden_type
|
||||||
.report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
|
.report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
|
||||||
.stash(
|
.stash(
|
||||||
@ -812,7 +812,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
|
|||||||
|
|
||||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
match self.fcx.fully_resolve(t) {
|
match self.fcx.fully_resolve(t) {
|
||||||
Ok(t) if self.fcx.tcx.trait_solver_next() => {
|
Ok(t) if self.fcx.next_trait_solver() => {
|
||||||
// We must normalize erasing regions here, since later lints
|
// We must normalize erasing regions here, since later lints
|
||||||
// expect that types that show up in the typeck are fully
|
// expect that types that show up in the typeck are fully
|
||||||
// normalized.
|
// normalized.
|
||||||
|
@ -82,6 +82,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
in_snapshot: self.in_snapshot.clone(),
|
in_snapshot: self.in_snapshot.clone(),
|
||||||
universe: self.universe.clone(),
|
universe: self.universe.clone(),
|
||||||
intercrate: self.intercrate,
|
intercrate: self.intercrate,
|
||||||
|
next_trait_solver: self.next_trait_solver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,11 +109,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
| (
|
| (
|
||||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
|
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
|
||||||
ty::Alias(AliasKind::Projection, _),
|
ty::Alias(AliasKind::Projection, _),
|
||||||
) if self.tcx.trait_solver_next() => {
|
) if self.next_trait_solver() => {
|
||||||
bug!()
|
bug!()
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, ty::Alias(..)) | (ty::Alias(..), _) if self.tcx.trait_solver_next() => {
|
(_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => {
|
||||||
relation.register_type_relate_obligation(a, b);
|
relation.register_type_relate_obligation(a, b);
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}
|
}
|
||||||
@ -227,9 +227,20 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
return self.unify_const_variable(vid, a, relation.param_env());
|
return self.unify_const_variable(vid, a, relation.param_env());
|
||||||
}
|
}
|
||||||
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
||||||
if self.tcx.features().generic_const_exprs || self.tcx.trait_solver_next() =>
|
if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
|
||||||
{
|
{
|
||||||
relation.register_const_equate_obligation(a, b);
|
let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) };
|
||||||
|
|
||||||
|
relation.register_predicates([ty::Binder::dummy(if self.next_trait_solver() {
|
||||||
|
ty::PredicateKind::AliasRelate(
|
||||||
|
a.into(),
|
||||||
|
b.into(),
|
||||||
|
ty::AliasRelationDirection::Equate,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ty::PredicateKind::ConstEquate(a, b)
|
||||||
|
})]);
|
||||||
|
|
||||||
return Ok(b);
|
return Ok(b);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -453,19 +464,6 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
|
|||||||
/// be used if control over the obligation causes is required.
|
/// be used if control over the obligation causes is required.
|
||||||
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
|
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
|
||||||
|
|
||||||
/// Register an obligation that both constants must be equal to each other.
|
|
||||||
///
|
|
||||||
/// If they aren't equal then the relation doesn't hold.
|
|
||||||
fn register_const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
|
|
||||||
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
|
|
||||||
|
|
||||||
self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() {
|
|
||||||
ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate)
|
|
||||||
} else {
|
|
||||||
ty::PredicateKind::ConstEquate(a, b)
|
|
||||||
})]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register an obligation that both types must be related to each other according to
|
/// Register an obligation that both types must be related to each other according to
|
||||||
/// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
|
/// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
|
||||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||||
|
@ -105,7 +105,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||||||
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
||||||
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
|
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
|
||||||
&& def_id.is_local()
|
&& def_id.is_local()
|
||||||
&& !self.tcx().trait_solver_next() =>
|
&& !self.fields.infcx.next_trait_solver() =>
|
||||||
{
|
{
|
||||||
self.fields.obligations.extend(
|
self.fields.obligations.extend(
|
||||||
infcx
|
infcx
|
||||||
|
@ -113,7 +113,7 @@ where
|
|||||||
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
||||||
if this.define_opaque_types() == DefineOpaqueTypes::Yes
|
if this.define_opaque_types() == DefineOpaqueTypes::Yes
|
||||||
&& def_id.is_local()
|
&& def_id.is_local()
|
||||||
&& !this.tcx().trait_solver_next() =>
|
&& !this.infcx().next_trait_solver() =>
|
||||||
{
|
{
|
||||||
this.register_obligations(
|
this.register_obligations(
|
||||||
infcx
|
infcx
|
||||||
|
@ -330,6 +330,8 @@ pub struct InferCtxt<'tcx> {
|
|||||||
/// there is no type that the user could *actually name* that
|
/// there is no type that the user could *actually name* that
|
||||||
/// would satisfy it. This avoids crippling inference, basically.
|
/// would satisfy it. This avoids crippling inference, basically.
|
||||||
pub intercrate: bool,
|
pub intercrate: bool,
|
||||||
|
|
||||||
|
next_trait_solver: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See the `error_reporting` module for more details.
|
/// See the `error_reporting` module for more details.
|
||||||
@ -545,6 +547,9 @@ pub struct InferCtxtBuilder<'tcx> {
|
|||||||
skip_leak_check: bool,
|
skip_leak_check: bool,
|
||||||
/// Whether we are in coherence mode.
|
/// Whether we are in coherence mode.
|
||||||
intercrate: bool,
|
intercrate: bool,
|
||||||
|
/// Whether we should use the new trait solver in the local inference context,
|
||||||
|
/// which affects things like which solver is used in `predicate_may_hold`.
|
||||||
|
next_trait_solver: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TyCtxtInferExt<'tcx> {
|
pub trait TyCtxtInferExt<'tcx> {
|
||||||
@ -559,6 +564,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
|
|||||||
considering_regions: true,
|
considering_regions: true,
|
||||||
skip_leak_check: false,
|
skip_leak_check: false,
|
||||||
intercrate: false,
|
intercrate: false,
|
||||||
|
next_trait_solver: self.next_trait_solver_globally(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -575,6 +581,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self {
|
||||||
|
self.next_trait_solver = next_trait_solver;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn intercrate(mut self, intercrate: bool) -> Self {
|
pub fn intercrate(mut self, intercrate: bool) -> Self {
|
||||||
self.intercrate = intercrate;
|
self.intercrate = intercrate;
|
||||||
self
|
self
|
||||||
@ -617,6 +628,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||||||
considering_regions,
|
considering_regions,
|
||||||
skip_leak_check,
|
skip_leak_check,
|
||||||
intercrate,
|
intercrate,
|
||||||
|
next_trait_solver,
|
||||||
} = *self;
|
} = *self;
|
||||||
InferCtxt {
|
InferCtxt {
|
||||||
tcx,
|
tcx,
|
||||||
@ -634,6 +646,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||||||
in_snapshot: Cell::new(false),
|
in_snapshot: Cell::new(false),
|
||||||
universe: Cell::new(ty::UniverseIndex::ROOT),
|
universe: Cell::new(ty::UniverseIndex::ROOT),
|
||||||
intercrate,
|
intercrate,
|
||||||
|
next_trait_solver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -670,6 +683,10 @@ pub struct CombinedSnapshot<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> InferCtxt<'tcx> {
|
impl<'tcx> InferCtxt<'tcx> {
|
||||||
|
pub fn next_trait_solver(&self) -> bool {
|
||||||
|
self.next_trait_solver
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a `TypeErrCtxt` for emitting various inference errors.
|
/// Creates a `TypeErrCtxt` for emitting various inference errors.
|
||||||
/// During typeck, use `FnCtxt::err_ctxt` instead.
|
/// During typeck, use `FnCtxt::err_ctxt` instead.
|
||||||
pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
|
pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
|
||||||
|
@ -491,12 +491,12 @@ where
|
|||||||
(
|
(
|
||||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
|
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
|
||||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
|
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
|
||||||
) if a_def_id == b_def_id || infcx.tcx.trait_solver_next() => {
|
) if a_def_id == b_def_id || infcx.next_trait_solver() => {
|
||||||
infcx.super_combine_tys(self, a, b).or_else(|err| {
|
infcx.super_combine_tys(self, a, b).or_else(|err| {
|
||||||
// This behavior is only there for the old solver, the new solver
|
// This behavior is only there for the old solver, the new solver
|
||||||
// shouldn't ever fail. Instead, it unconditionally emits an
|
// shouldn't ever fail. Instead, it unconditionally emits an
|
||||||
// alias-relate goal.
|
// alias-relate goal.
|
||||||
assert!(!self.tcx().trait_solver_next());
|
assert!(!self.infcx.next_trait_solver());
|
||||||
self.tcx().sess.delay_span_bug(
|
self.tcx().sess.delay_span_bug(
|
||||||
self.delegate.span(),
|
self.delegate.span(),
|
||||||
"failure to relate an opaque to itself should result in an error later on",
|
"failure to relate an opaque to itself should result in an error later on",
|
||||||
@ -506,7 +506,7 @@ where
|
|||||||
}
|
}
|
||||||
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
|
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
|
||||||
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
||||||
if def_id.is_local() && !self.tcx().trait_solver_next() =>
|
if def_id.is_local() && !self.infcx.next_trait_solver() =>
|
||||||
{
|
{
|
||||||
self.relate_opaques(a, b)
|
self.relate_opaques(a, b)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> InferOk<'tcx, T> {
|
) -> InferOk<'tcx, T> {
|
||||||
// We handle opaque types differently in the new solver.
|
// We handle opaque types differently in the new solver.
|
||||||
if self.tcx.trait_solver_next() {
|
if self.next_trait_solver() {
|
||||||
return InferOk { value, obligations: vec![] };
|
return InferOk { value, obligations: vec![] };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +578,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
hidden_ty: Ty<'tcx>,
|
hidden_ty: Ty<'tcx>,
|
||||||
) -> InferResult<'tcx, ()> {
|
) -> InferResult<'tcx, ()> {
|
||||||
assert!(self.tcx.trait_solver_next());
|
assert!(self.next_trait_solver());
|
||||||
let origin = self
|
let origin = self
|
||||||
.opaque_type_origin(opaque_type_key.def_id)
|
.opaque_type_origin(opaque_type_key.def_id)
|
||||||
.expect("should be called for defining usages only");
|
.expect("should be called for defining usages only");
|
||||||
@ -614,7 +614,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
ty::Alias(ty::Projection, projection_ty)
|
ty::Alias(ty::Projection, projection_ty)
|
||||||
if !projection_ty.has_escaping_bound_vars()
|
if !projection_ty.has_escaping_bound_vars()
|
||||||
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id)
|
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id)
|
||||||
&& !tcx.trait_solver_next() =>
|
&& !self.next_trait_solver() =>
|
||||||
{
|
{
|
||||||
self.infer_projection(
|
self.infer_projection(
|
||||||
param_env,
|
param_env,
|
||||||
|
@ -21,7 +21,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
recursion_depth: usize,
|
recursion_depth: usize,
|
||||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
if self.tcx.trait_solver_next() {
|
if self.next_trait_solver() {
|
||||||
// FIXME(-Ztrait-solver=next): Instead of branching here,
|
// FIXME(-Ztrait-solver=next): Instead of branching here,
|
||||||
// completely change the normalization routine with the new solver.
|
// completely change the normalization routine with the new solver.
|
||||||
//
|
//
|
||||||
|
@ -132,7 +132,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||||||
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
||||||
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
|
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
|
||||||
&& def_id.is_local()
|
&& def_id.is_local()
|
||||||
&& !self.tcx().trait_solver_next() =>
|
&& !self.fields.infcx.next_trait_solver() =>
|
||||||
{
|
{
|
||||||
self.fields.obligations.extend(
|
self.fields.obligations.extend(
|
||||||
infcx
|
infcx
|
||||||
|
@ -2333,10 +2333,18 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
self.opt_local_def_id_to_hir_id(local_def_id).unwrap()
|
self.opt_local_def_id_to_hir_id(local_def_id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_solver_next(self) -> bool {
|
pub fn next_trait_solver_globally(self) -> bool {
|
||||||
self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next
|
self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn next_trait_solver_in_coherence(self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self.sess.opts.unstable_opts.trait_solver,
|
||||||
|
rustc_session::config::TraitSolver::Next
|
||||||
|
| rustc_session::config::TraitSolver::NextCoherence
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool {
|
pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool {
|
||||||
self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty
|
self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty
|
||||||
}
|
}
|
||||||
|
@ -610,6 +610,8 @@ pub enum TraitSolver {
|
|||||||
Chalk,
|
Chalk,
|
||||||
/// Experimental trait solver in `rustc_trait_selection::solve`
|
/// Experimental trait solver in `rustc_trait_selection::solve`
|
||||||
Next,
|
Next,
|
||||||
|
/// Use the new trait solver during coherence
|
||||||
|
NextCoherence,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Input {
|
pub enum Input {
|
||||||
|
@ -986,6 +986,7 @@ mod parse {
|
|||||||
Some("classic") => *slot = TraitSolver::Classic,
|
Some("classic") => *slot = TraitSolver::Classic,
|
||||||
Some("chalk") => *slot = TraitSolver::Chalk,
|
Some("chalk") => *slot = TraitSolver::Chalk,
|
||||||
Some("next") => *slot = TraitSolver::Next,
|
Some("next") => *slot = TraitSolver::Next,
|
||||||
|
Some("next-coherence") => *slot = TraitSolver::NextCoherence,
|
||||||
// default trait solver is subject to change..
|
// default trait solver is subject to change..
|
||||||
Some("default") => *slot = TraitSolver::Classic,
|
Some("default") => *slot = TraitSolver::Classic,
|
||||||
_ => return false,
|
_ => return false,
|
||||||
|
195
compiler/rustc_trait_selection/src/solve/alias_relate.rs
Normal file
195
compiler/rustc_trait_selection/src/solve/alias_relate.rs
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
use super::{EvalCtxt, SolverMode};
|
||||||
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||||
|
use rustc_middle::ty;
|
||||||
|
|
||||||
|
/// We may need to invert the alias relation direction if dealing an alias on the RHS.
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Invert {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
|
pub(super) fn compute_alias_relate_goal(
|
||||||
|
&mut self,
|
||||||
|
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
|
||||||
|
if lhs.is_infer() || rhs.is_infer() {
|
||||||
|
bug!(
|
||||||
|
"`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
|
||||||
|
(None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
|
||||||
|
|
||||||
|
// RHS is not a projection, only way this is true is if LHS normalizes-to RHS
|
||||||
|
(Some(alias_lhs), None) => self.assemble_normalizes_to_candidate(
|
||||||
|
param_env,
|
||||||
|
alias_lhs,
|
||||||
|
rhs,
|
||||||
|
direction,
|
||||||
|
Invert::No,
|
||||||
|
),
|
||||||
|
|
||||||
|
// LHS is not a projection, only way this is true is if RHS normalizes-to LHS
|
||||||
|
(None, Some(alias_rhs)) => self.assemble_normalizes_to_candidate(
|
||||||
|
param_env,
|
||||||
|
alias_rhs,
|
||||||
|
lhs,
|
||||||
|
direction,
|
||||||
|
Invert::Yes,
|
||||||
|
),
|
||||||
|
|
||||||
|
(Some(alias_lhs), Some(alias_rhs)) => {
|
||||||
|
debug!("both sides are aliases");
|
||||||
|
|
||||||
|
let mut candidates = Vec::new();
|
||||||
|
// LHS normalizes-to RHS
|
||||||
|
candidates.extend(self.assemble_normalizes_to_candidate(
|
||||||
|
param_env,
|
||||||
|
alias_lhs,
|
||||||
|
rhs,
|
||||||
|
direction,
|
||||||
|
Invert::No,
|
||||||
|
));
|
||||||
|
// RHS normalizes-to RHS
|
||||||
|
candidates.extend(self.assemble_normalizes_to_candidate(
|
||||||
|
param_env,
|
||||||
|
alias_rhs,
|
||||||
|
lhs,
|
||||||
|
direction,
|
||||||
|
Invert::Yes,
|
||||||
|
));
|
||||||
|
// Relate via substs
|
||||||
|
let subst_relate_response = self
|
||||||
|
.assemble_subst_relate_candidate(param_env, alias_lhs, alias_rhs, direction);
|
||||||
|
candidates.extend(subst_relate_response);
|
||||||
|
debug!(?candidates);
|
||||||
|
|
||||||
|
if let Some(merged) = self.try_merge_responses(&candidates) {
|
||||||
|
Ok(merged)
|
||||||
|
} else {
|
||||||
|
// When relating two aliases and we have ambiguity, we prefer
|
||||||
|
// relating the generic arguments of the aliases over normalizing
|
||||||
|
// them. This is necessary for inference during typeck.
|
||||||
|
//
|
||||||
|
// As this is incomplete, we must not do so during coherence.
|
||||||
|
match self.solver_mode() {
|
||||||
|
SolverMode::Normal => {
|
||||||
|
if let Ok(subst_relate_response) = subst_relate_response {
|
||||||
|
Ok(subst_relate_response)
|
||||||
|
} else if let Ok(bidirectional_normalizes_to_response) = self
|
||||||
|
.assemble_bidirectional_normalizes_to_candidate(
|
||||||
|
param_env, lhs, rhs, direction,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Ok(bidirectional_normalizes_to_response)
|
||||||
|
} else {
|
||||||
|
self.flounder(&candidates)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SolverMode::Coherence => self.flounder(&candidates),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
|
fn assemble_normalizes_to_candidate(
|
||||||
|
&mut self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
alias: ty::AliasTy<'tcx>,
|
||||||
|
other: ty::Term<'tcx>,
|
||||||
|
direction: ty::AliasRelationDirection,
|
||||||
|
invert: Invert,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
self.probe(|ecx| {
|
||||||
|
ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalizes_to_inner(
|
||||||
|
&mut self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
alias: ty::AliasTy<'tcx>,
|
||||||
|
other: ty::Term<'tcx>,
|
||||||
|
direction: ty::AliasRelationDirection,
|
||||||
|
invert: Invert,
|
||||||
|
) -> Result<(), NoSolution> {
|
||||||
|
let other = match direction {
|
||||||
|
// This is purely an optimization.
|
||||||
|
ty::AliasRelationDirection::Equate => other,
|
||||||
|
|
||||||
|
ty::AliasRelationDirection::Subtype => {
|
||||||
|
let fresh = self.next_term_infer_of_kind(other);
|
||||||
|
let (sub, sup) = match invert {
|
||||||
|
Invert::No => (fresh, other),
|
||||||
|
Invert::Yes => (other, fresh),
|
||||||
|
};
|
||||||
|
self.sub(param_env, sub, sup)?;
|
||||||
|
fresh
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.add_goal(Goal::new(
|
||||||
|
self.tcx(),
|
||||||
|
param_env,
|
||||||
|
ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }),
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assemble_subst_relate_candidate(
|
||||||
|
&mut self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
alias_lhs: ty::AliasTy<'tcx>,
|
||||||
|
alias_rhs: ty::AliasTy<'tcx>,
|
||||||
|
direction: ty::AliasRelationDirection,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
self.probe(|ecx| {
|
||||||
|
match direction {
|
||||||
|
ty::AliasRelationDirection::Equate => {
|
||||||
|
ecx.eq(param_env, alias_lhs, alias_rhs)?;
|
||||||
|
}
|
||||||
|
ty::AliasRelationDirection::Subtype => {
|
||||||
|
ecx.sub(param_env, alias_lhs, alias_rhs)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assemble_bidirectional_normalizes_to_candidate(
|
||||||
|
&mut self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
lhs: ty::Term<'tcx>,
|
||||||
|
rhs: ty::Term<'tcx>,
|
||||||
|
direction: ty::AliasRelationDirection,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
self.probe(|ecx| {
|
||||||
|
ecx.normalizes_to_inner(
|
||||||
|
param_env,
|
||||||
|
lhs.to_alias_ty(ecx.tcx()).unwrap(),
|
||||||
|
rhs,
|
||||||
|
direction,
|
||||||
|
Invert::No,
|
||||||
|
)?;
|
||||||
|
ecx.normalizes_to_inner(
|
||||||
|
param_env,
|
||||||
|
rhs.to_alias_ty(ecx.tcx()).unwrap(),
|
||||||
|
lhs,
|
||||||
|
direction,
|
||||||
|
Invert::Yes,
|
||||||
|
)?;
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -187,6 +187,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||||||
let (ref infcx, input, var_values) = tcx
|
let (ref infcx, input, var_values) = tcx
|
||||||
.infer_ctxt()
|
.infer_ctxt()
|
||||||
.intercrate(intercrate)
|
.intercrate(intercrate)
|
||||||
|
.with_next_trait_solver(true)
|
||||||
.with_opaque_type_inference(canonical_input.value.anchor)
|
.with_opaque_type_inference(canonical_input.value.anchor)
|
||||||
.build_with_canonical(DUMMY_SP, &canonical_input);
|
.build_with_canonical(DUMMY_SP, &canonical_input);
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ use rustc_middle::ty::{
|
|||||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod alias_relate;
|
||||||
mod assembly;
|
mod assembly;
|
||||||
mod canonicalize;
|
mod canonicalize;
|
||||||
mod eval_ctxt;
|
mod eval_ctxt;
|
||||||
@ -154,142 +155,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self), ret)]
|
|
||||||
fn compute_alias_relate_goal(
|
|
||||||
&mut self,
|
|
||||||
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
|
|
||||||
) -> QueryResult<'tcx> {
|
|
||||||
let tcx = self.tcx();
|
|
||||||
// We may need to invert the alias relation direction if dealing an alias on the RHS.
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Invert {
|
|
||||||
No,
|
|
||||||
Yes,
|
|
||||||
}
|
|
||||||
let evaluate_normalizes_to =
|
|
||||||
|ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| {
|
|
||||||
let span = tracing::span!(
|
|
||||||
tracing::Level::DEBUG,
|
|
||||||
"compute_alias_relate_goal(evaluate_normalizes_to)",
|
|
||||||
?alias,
|
|
||||||
?other,
|
|
||||||
?direction,
|
|
||||||
?invert
|
|
||||||
);
|
|
||||||
let _enter = span.enter();
|
|
||||||
let result = ecx.probe(|ecx| {
|
|
||||||
let other = match direction {
|
|
||||||
// This is purely an optimization.
|
|
||||||
ty::AliasRelationDirection::Equate => other,
|
|
||||||
|
|
||||||
ty::AliasRelationDirection::Subtype => {
|
|
||||||
let fresh = ecx.next_term_infer_of_kind(other);
|
|
||||||
let (sub, sup) = match invert {
|
|
||||||
Invert::No => (fresh, other),
|
|
||||||
Invert::Yes => (other, fresh),
|
|
||||||
};
|
|
||||||
ecx.sub(goal.param_env, sub, sup)?;
|
|
||||||
fresh
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ecx.add_goal(goal.with(
|
|
||||||
tcx,
|
|
||||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
|
||||||
projection_ty: alias,
|
|
||||||
term: other,
|
|
||||||
}),
|
|
||||||
));
|
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
|
||||||
});
|
|
||||||
debug!(?result);
|
|
||||||
result
|
|
||||||
};
|
|
||||||
|
|
||||||
let (lhs, rhs, direction) = goal.predicate;
|
|
||||||
|
|
||||||
if lhs.is_infer() || rhs.is_infer() {
|
|
||||||
bug!(
|
|
||||||
"`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
|
|
||||||
(None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
|
|
||||||
|
|
||||||
// RHS is not a projection, only way this is true is if LHS normalizes-to RHS
|
|
||||||
(Some(alias_lhs), None) => {
|
|
||||||
evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LHS is not a projection, only way this is true is if RHS normalizes-to LHS
|
|
||||||
(None, Some(alias_rhs)) => {
|
|
||||||
evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes)
|
|
||||||
}
|
|
||||||
|
|
||||||
(Some(alias_lhs), Some(alias_rhs)) => {
|
|
||||||
debug!("both sides are aliases");
|
|
||||||
|
|
||||||
let mut candidates = Vec::new();
|
|
||||||
// LHS normalizes-to RHS
|
|
||||||
candidates.extend(evaluate_normalizes_to(
|
|
||||||
self,
|
|
||||||
alias_lhs,
|
|
||||||
rhs,
|
|
||||||
direction,
|
|
||||||
Invert::No,
|
|
||||||
));
|
|
||||||
// RHS normalizes-to RHS
|
|
||||||
candidates.extend(evaluate_normalizes_to(
|
|
||||||
self,
|
|
||||||
alias_rhs,
|
|
||||||
lhs,
|
|
||||||
direction,
|
|
||||||
Invert::Yes,
|
|
||||||
));
|
|
||||||
// Relate via substs
|
|
||||||
let subst_relate_response = self.probe(|ecx| {
|
|
||||||
let span = tracing::span!(
|
|
||||||
tracing::Level::DEBUG,
|
|
||||||
"compute_alias_relate_goal(relate_via_substs)",
|
|
||||||
?alias_lhs,
|
|
||||||
?alias_rhs,
|
|
||||||
?direction
|
|
||||||
);
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
match direction {
|
|
||||||
ty::AliasRelationDirection::Equate => {
|
|
||||||
ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
|
|
||||||
}
|
|
||||||
ty::AliasRelationDirection::Subtype => {
|
|
||||||
ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
|
||||||
});
|
|
||||||
candidates.extend(subst_relate_response);
|
|
||||||
debug!(?candidates);
|
|
||||||
|
|
||||||
if let Some(merged) = self.try_merge_responses(&candidates) {
|
|
||||||
Ok(merged)
|
|
||||||
} else {
|
|
||||||
// When relating two aliases and we have ambiguity, we prefer
|
|
||||||
// relating the generic arguments of the aliases over normalizing
|
|
||||||
// them. This is necessary for inference during typeck.
|
|
||||||
//
|
|
||||||
// As this is incomplete, we must not do so during coherence.
|
|
||||||
match (self.solver_mode(), subst_relate_response) {
|
|
||||||
(SolverMode::Normal, Ok(response)) => Ok(response),
|
|
||||||
(SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => {
|
|
||||||
self.flounder(&candidates)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self), ret)]
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
fn compute_const_arg_has_type_goal(
|
fn compute_const_arg_has_type_goal(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -182,6 +182,7 @@ fn overlap<'tcx>(
|
|||||||
.with_opaque_type_inference(DefiningAnchor::Bubble)
|
.with_opaque_type_inference(DefiningAnchor::Bubble)
|
||||||
.skip_leak_check(skip_leak_check.is_yes())
|
.skip_leak_check(skip_leak_check.is_yes())
|
||||||
.intercrate(true)
|
.intercrate(true)
|
||||||
|
.with_next_trait_solver(tcx.next_trait_solver_in_coherence())
|
||||||
.build();
|
.build();
|
||||||
let selcx = &mut SelectionContext::new(&infcx);
|
let selcx = &mut SelectionContext::new(&infcx);
|
||||||
if track_ambiguity_causes.is_yes() {
|
if track_ambiguity_causes.is_yes() {
|
||||||
|
@ -27,24 +27,42 @@ use rustc_session::config::TraitSolver;
|
|||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
pub trait TraitEngineExt<'tcx> {
|
pub trait TraitEngineExt<'tcx> {
|
||||||
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
|
fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>;
|
||||||
fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self>;
|
fn new_in_snapshot(infcx: &InferCtxt<'tcx>) -> Box<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
||||||
fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
|
fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> {
|
||||||
match tcx.sess.opts.unstable_opts.trait_solver {
|
match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) {
|
||||||
TraitSolver::Classic => Box::new(FulfillmentContext::new()),
|
(TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => {
|
||||||
TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new()),
|
Box::new(FulfillmentContext::new())
|
||||||
TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()),
|
}
|
||||||
|
(TraitSolver::Next | TraitSolver::NextCoherence, true) => {
|
||||||
|
Box::new(NextFulfillmentCtxt::new())
|
||||||
|
}
|
||||||
|
(TraitSolver::Chalk, false) => Box::new(ChalkFulfillmentContext::new()),
|
||||||
|
_ => bug!(
|
||||||
|
"incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})",
|
||||||
|
infcx.tcx.sess.opts.unstable_opts.trait_solver,
|
||||||
|
infcx.next_trait_solver()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
|
fn new_in_snapshot(infcx: &InferCtxt<'tcx>) -> Box<Self> {
|
||||||
match tcx.sess.opts.unstable_opts.trait_solver {
|
match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) {
|
||||||
TraitSolver::Classic => Box::new(FulfillmentContext::new_in_snapshot()),
|
(TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => {
|
||||||
TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new_in_snapshot()),
|
Box::new(FulfillmentContext::new_in_snapshot())
|
||||||
TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()),
|
}
|
||||||
|
(TraitSolver::Next | TraitSolver::NextCoherence, true) => {
|
||||||
|
Box::new(NextFulfillmentCtxt::new())
|
||||||
|
}
|
||||||
|
(TraitSolver::Chalk, false) => Box::new(ChalkFulfillmentContext::new_in_snapshot()),
|
||||||
|
_ => bug!(
|
||||||
|
"incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})",
|
||||||
|
infcx.tcx.sess.opts.unstable_opts.trait_solver,
|
||||||
|
infcx.next_trait_solver()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,11 +76,11 @@ pub struct ObligationCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
||||||
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
|
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||||
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) }
|
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_in_snapshot(infcx: &'a InferCtxt<'tcx>) -> Self {
|
pub fn new_in_snapshot(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||||
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new_in_snapshot(infcx.tcx)) }
|
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new_in_snapshot(infcx)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
|
pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
|
||||||
|
@ -1047,7 +1047,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
// (which may fail).
|
// (which may fail).
|
||||||
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
||||||
}
|
}
|
||||||
TraitSolver::Chalk | TraitSolver::Next => {
|
TraitSolver::Chalk | TraitSolver::Next | TraitSolver::NextCoherence => {
|
||||||
// FIXME: we'll need a better message which takes into account
|
// FIXME: we'll need a better message which takes into account
|
||||||
// which bounds actually failed to hold.
|
// which bounds actually failed to hold.
|
||||||
self.tcx.sess.struct_span_err(
|
self.tcx.sess.struct_span_err(
|
||||||
|
@ -78,7 +78,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||||||
_ => obligation.param_env.without_const(),
|
_ => obligation.param_env.without_const(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.tcx.trait_solver_next() {
|
if self.next_trait_solver() {
|
||||||
self.probe(|snapshot| {
|
self.probe(|snapshot| {
|
||||||
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new();
|
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new();
|
||||||
fulfill_cx.register_predicate_obligation(self, obligation.clone());
|
fulfill_cx.register_predicate_obligation(self, obligation.clone());
|
||||||
|
@ -146,7 +146,7 @@ where
|
|||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
|
) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
|
||||||
if infcx.tcx.trait_solver_next() {
|
if infcx.next_trait_solver() {
|
||||||
return Ok(scrape_region_constraints(
|
return Ok(scrape_region_constraints(
|
||||||
infcx,
|
infcx,
|
||||||
|ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self),
|
|ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self),
|
||||||
|
@ -539,7 +539,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
self.evaluation_probe(|this| {
|
self.evaluation_probe(|this| {
|
||||||
let goal =
|
let goal =
|
||||||
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
|
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
|
||||||
let mut result = if this.tcx().trait_solver_next() {
|
let mut result = if this.infcx.next_trait_solver() {
|
||||||
this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])?
|
this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])?
|
||||||
} else {
|
} else {
|
||||||
this.evaluate_predicate_recursively(
|
this.evaluate_predicate_recursively(
|
||||||
@ -593,7 +593,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
where
|
where
|
||||||
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
|
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
if self.tcx().trait_solver_next() {
|
if self.infcx.next_trait_solver() {
|
||||||
self.evaluate_predicates_recursively_in_new_solver(predicates)
|
self.evaluate_predicates_recursively_in_new_solver(predicates)
|
||||||
} else {
|
} else {
|
||||||
let mut result = EvaluatedToOk;
|
let mut result = EvaluatedToOk;
|
||||||
|
@ -21,7 +21,7 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
|
|||||||
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
|
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
|
||||||
assert!(!ty.is_ty_var(), "should have resolved vars before calling");
|
assert!(!ty.is_ty_var(), "should have resolved vars before calling");
|
||||||
|
|
||||||
if self.infcx.tcx.trait_solver_next() {
|
if self.infcx.next_trait_solver() {
|
||||||
while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() {
|
while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() {
|
||||||
let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
|
let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
|
||||||
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
||||||
|
@ -55,7 +55,7 @@ pub fn codegen_select_candidate<'tcx>(
|
|||||||
// Currently, we use a fulfillment context to completely resolve
|
// Currently, we use a fulfillment context to completely resolve
|
||||||
// all nested obligations. This is because they can inform the
|
// all nested obligations. This is because they can inform the
|
||||||
// inference of the impl's type parameters.
|
// inference of the impl's type parameters.
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
|
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(&infcx);
|
||||||
let impl_source = selection.map(|predicate| {
|
let impl_source = selection.map(|predicate| {
|
||||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||||
});
|
});
|
||||||
|
@ -16,7 +16,7 @@ fn evaluate_obligation<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
canonical_goal: CanonicalPredicateGoal<'tcx>,
|
canonical_goal: CanonicalPredicateGoal<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
assert!(!tcx.trait_solver_next());
|
assert!(!tcx.next_trait_solver_globally());
|
||||||
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
|
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
|
||||||
// HACK This bubble is required for this tests to pass:
|
// HACK This bubble is required for this tests to pass:
|
||||||
// impl-trait/issue99642.rs
|
// impl-trait/issue99642.rs
|
||||||
|
@ -1358,7 +1358,12 @@ impl Step for Sysroot {
|
|||||||
// newly compiled std, not the downloaded std.
|
// newly compiled std, not the downloaded std.
|
||||||
add_filtered_files("lib", builder.config.ci_rust_std_contents());
|
add_filtered_files("lib", builder.config.ci_rust_std_contents());
|
||||||
|
|
||||||
let filtered_extensions = [OsStr::new("rmeta"), OsStr::new("rlib"), OsStr::new("so")];
|
let filtered_extensions = [
|
||||||
|
OsStr::new("rmeta"),
|
||||||
|
OsStr::new("rlib"),
|
||||||
|
// FIXME: this is wrong when compiler.host != build, but we don't support that today
|
||||||
|
OsStr::new(std::env::consts::DLL_EXTENSION),
|
||||||
|
];
|
||||||
let ci_rustc_dir = builder.ci_rustc_dir(builder.config.build);
|
let ci_rustc_dir = builder.ci_rustc_dir(builder.config.build);
|
||||||
builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| {
|
builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| {
|
||||||
if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) {
|
if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) {
|
||||||
|
@ -14,7 +14,7 @@ use rustc_span::hygiene::MacroKind;
|
|||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use std::{iter, mem};
|
use std::mem;
|
||||||
|
|
||||||
use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt};
|
use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt};
|
||||||
use crate::core;
|
use crate::core;
|
||||||
@ -291,27 +291,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||||||
if !please_inline {
|
if !please_inline {
|
||||||
let inherits_hidden = inherits_doc_hidden(tcx, res_did, None);
|
let inherits_hidden = inherits_doc_hidden(tcx, res_did, None);
|
||||||
// Only inline if requested or if the item would otherwise be stripped.
|
// Only inline if requested or if the item would otherwise be stripped.
|
||||||
//
|
|
||||||
// If it's a doc hidden module, we need to keep it in case some of its inner items
|
|
||||||
// are re-exported.
|
|
||||||
if (!is_private && !inherits_hidden) || (
|
if (!is_private && !inherits_hidden) || (
|
||||||
is_hidden &&
|
is_hidden &&
|
||||||
|
// If it's a doc hidden module, we need to keep it in case some of its inner items
|
||||||
|
// are re-exported.
|
||||||
!matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. }))
|
!matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. }))
|
||||||
) {
|
) ||
|
||||||
return false;
|
|
||||||
} else if let Some(item_def_id) = reexport_chain(tcx, def_id, res_did).iter()
|
|
||||||
.flat_map(|reexport| reexport.id()).map(|id| id.expect_local())
|
|
||||||
.chain(iter::once(res_did)).nth(1) &&
|
|
||||||
item_def_id != def_id &&
|
|
||||||
self
|
|
||||||
.cx
|
|
||||||
.cache
|
|
||||||
.effective_visibilities
|
|
||||||
.is_directly_public(tcx, item_def_id.to_def_id()) &&
|
|
||||||
!tcx.is_doc_hidden(item_def_id) &&
|
|
||||||
!inherits_doc_hidden(tcx, item_def_id, None)
|
|
||||||
{
|
|
||||||
// The imported item is public and not `doc(hidden)` so no need to inline it.
|
// The imported item is public and not `doc(hidden)` so no need to inline it.
|
||||||
|
self.reexport_public_and_not_hidden(def_id, res_did)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,6 +347,28 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the item is visible, meaning it's not `#[doc(hidden)]` or private.
|
||||||
|
///
|
||||||
|
/// This function takes into account the entire re-export `use` chain, so it needs the
|
||||||
|
/// ID of the "leaf" `use` and the ID of the "root" item.
|
||||||
|
fn reexport_public_and_not_hidden(
|
||||||
|
&self,
|
||||||
|
import_def_id: LocalDefId,
|
||||||
|
target_def_id: LocalDefId,
|
||||||
|
) -> bool {
|
||||||
|
let tcx = self.cx.tcx;
|
||||||
|
let item_def_id = reexport_chain(tcx, import_def_id, target_def_id)
|
||||||
|
.iter()
|
||||||
|
.flat_map(|reexport| reexport.id())
|
||||||
|
.map(|id| id.expect_local())
|
||||||
|
.nth(1)
|
||||||
|
.unwrap_or(target_def_id);
|
||||||
|
item_def_id != import_def_id
|
||||||
|
&& self.cx.cache.effective_visibilities.is_directly_public(tcx, item_def_id.to_def_id())
|
||||||
|
&& !tcx.is_doc_hidden(item_def_id)
|
||||||
|
&& !inherits_doc_hidden(tcx, item_def_id, None)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_to_current_mod(
|
fn add_to_current_mod(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -108,6 +108,7 @@ string_enum! {
|
|||||||
Polonius => "polonius",
|
Polonius => "polonius",
|
||||||
Chalk => "chalk",
|
Chalk => "chalk",
|
||||||
NextSolver => "next-solver",
|
NextSolver => "next-solver",
|
||||||
|
NextSolverCoherence => "next-solver-coherence",
|
||||||
SplitDwarf => "split-dwarf",
|
SplitDwarf => "split-dwarf",
|
||||||
SplitDwarfSingle => "split-dwarf-single",
|
SplitDwarfSingle => "split-dwarf-single",
|
||||||
}
|
}
|
||||||
|
@ -2127,6 +2127,9 @@ impl<'test> TestCx<'test> {
|
|||||||
Some(CompareMode::NextSolver) => {
|
Some(CompareMode::NextSolver) => {
|
||||||
rustc.args(&["-Ztrait-solver=next"]);
|
rustc.args(&["-Ztrait-solver=next"]);
|
||||||
}
|
}
|
||||||
|
Some(CompareMode::NextSolverCoherence) => {
|
||||||
|
rustc.args(&["-Ztrait-solver=next-coherence"]);
|
||||||
|
}
|
||||||
Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => {
|
Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => {
|
||||||
rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
|
rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
|
||||||
}
|
}
|
||||||
|
49
tests/ui/macros/issue-112342-1.rs
Normal file
49
tests/ui/macros/issue-112342-1.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// same as #95267, ignore doc comment although it's a bug.
|
||||||
|
|
||||||
|
macro_rules! m1 {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
///
|
||||||
|
)*
|
||||||
|
//~^^^ERROR repetition matches empty token tree
|
||||||
|
) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m1! {}
|
||||||
|
|
||||||
|
macro_rules! m2 {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
///
|
||||||
|
)+
|
||||||
|
//~^^^ERROR repetition matches empty token tree
|
||||||
|
) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m2! {}
|
||||||
|
|
||||||
|
macro_rules! m3 {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
///
|
||||||
|
)?
|
||||||
|
//~^^^ERROR repetition matches empty token tree
|
||||||
|
) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m3! {}
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! m4 {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
///
|
||||||
|
///
|
||||||
|
)*
|
||||||
|
//~^^^^ERROR repetition matches empty token tree
|
||||||
|
) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m4! {}
|
||||||
|
|
||||||
|
fn main() {}
|
64
tests/ui/macros/issue-112342-1.stderr
Normal file
64
tests/ui/macros/issue-112342-1.stderr
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
note: doc comments are ignored in matcher position
|
||||||
|
--> $DIR/issue-112342-1.rs:6:13
|
||||||
|
|
|
||||||
|
LL | ///
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: repetition matches empty token tree
|
||||||
|
--> $DIR/issue-112342-1.rs:5:10
|
||||||
|
|
|
||||||
|
LL | $(
|
||||||
|
| __________^
|
||||||
|
LL | | ///
|
||||||
|
LL | | )*
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
note: doc comments are ignored in matcher position
|
||||||
|
--> $DIR/issue-112342-1.rs:17:13
|
||||||
|
|
|
||||||
|
LL | ///
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: repetition matches empty token tree
|
||||||
|
--> $DIR/issue-112342-1.rs:16:10
|
||||||
|
|
|
||||||
|
LL | $(
|
||||||
|
| __________^
|
||||||
|
LL | | ///
|
||||||
|
LL | | )+
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
note: doc comments are ignored in matcher position
|
||||||
|
--> $DIR/issue-112342-1.rs:28:13
|
||||||
|
|
|
||||||
|
LL | ///
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: repetition matches empty token tree
|
||||||
|
--> $DIR/issue-112342-1.rs:27:10
|
||||||
|
|
|
||||||
|
LL | $(
|
||||||
|
| __________^
|
||||||
|
LL | | ///
|
||||||
|
LL | | )?
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
note: doc comments are ignored in matcher position
|
||||||
|
--> $DIR/issue-112342-1.rs:40:13
|
||||||
|
|
|
||||||
|
LL | / ///
|
||||||
|
LL | | ///
|
||||||
|
| |_______________^
|
||||||
|
|
||||||
|
error: repetition matches empty token tree
|
||||||
|
--> $DIR/issue-112342-1.rs:39:10
|
||||||
|
|
|
||||||
|
LL | $(
|
||||||
|
| __________^
|
||||||
|
LL | | ///
|
||||||
|
LL | | ///
|
||||||
|
LL | | )*
|
||||||
|
| |_________^
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
39
tests/ui/macros/issue-112342-2.rs
Normal file
39
tests/ui/macros/issue-112342-2.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
// same as #95267, ignore doc comment although it's a bug.
|
||||||
|
|
||||||
|
macro_rules! m1 {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
///
|
||||||
|
$expr: expr,
|
||||||
|
)*
|
||||||
|
) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m1! {}
|
||||||
|
|
||||||
|
macro_rules! m2 {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
///
|
||||||
|
$expr: expr,
|
||||||
|
///
|
||||||
|
)*
|
||||||
|
) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m2! {}
|
||||||
|
|
||||||
|
macro_rules! m3 {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
///
|
||||||
|
$tt: tt,
|
||||||
|
)*
|
||||||
|
) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m3! {}
|
||||||
|
|
||||||
|
fn main() {}
|
24
tests/ui/macros/issue-112342-2.stderr
Normal file
24
tests/ui/macros/issue-112342-2.stderr
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
note: doc comments are ignored in matcher position
|
||||||
|
--> $DIR/issue-112342-2.rs:8:13
|
||||||
|
|
|
||||||
|
LL | ///
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
note: doc comments are ignored in matcher position
|
||||||
|
--> $DIR/issue-112342-2.rs:19:13
|
||||||
|
|
|
||||||
|
LL | ///
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
note: doc comments are ignored in matcher position
|
||||||
|
--> $DIR/issue-112342-2.rs:21:13
|
||||||
|
|
|
||||||
|
LL | ///
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
note: doc comments are ignored in matcher position
|
||||||
|
--> $DIR/issue-112342-2.rs:31:13
|
||||||
|
|
|
||||||
|
LL | ///
|
||||||
|
| ^^^
|
||||||
|
|
@ -0,0 +1,12 @@
|
|||||||
|
error[E0119]: conflicting implementations of trait `Overlap` for type `u32`
|
||||||
|
--> $DIR/specialization-default-items-drop-coherence.rs:29:1
|
||||||
|
|
|
||||||
|
LL | impl Overlap for u32 {
|
||||||
|
| -------------------- first implementation here
|
||||||
|
...
|
||||||
|
LL | impl Overlap for <u32 as Default>::Id {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
@ -0,0 +1,12 @@
|
|||||||
|
error[E0119]: conflicting implementations of trait `Overlap` for type `u32`
|
||||||
|
--> $DIR/specialization-default-items-drop-coherence.rs:29:1
|
||||||
|
|
|
||||||
|
LL | impl Overlap for u32 {
|
||||||
|
| -------------------- first implementation here
|
||||||
|
...
|
||||||
|
LL | impl Overlap for <u32 as Default>::Id {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
@ -1,5 +1,8 @@
|
|||||||
// check-pass
|
// revisions: classic coherence next
|
||||||
// known-bug: #105782
|
//[next] compile-flags: -Ztrait-solver=next
|
||||||
|
//[coherence] compile-flags: -Ztrait-solver=next-coherence
|
||||||
|
//[classic] check-pass
|
||||||
|
//[classic] known-bug: #105782
|
||||||
|
|
||||||
// Should fail. Default items completely drop candidates instead of ambiguity,
|
// Should fail. Default items completely drop candidates instead of ambiguity,
|
||||||
// which is unsound during coherence, since coherence requires completeness.
|
// which is unsound during coherence, since coherence requires completeness.
|
||||||
@ -24,6 +27,8 @@ impl Overlap for u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Overlap for <u32 as Default>::Id {
|
impl Overlap for <u32 as Default>::Id {
|
||||||
|
//[coherence]~^ ERROR conflicting implementations of trait `Overlap` for type `u32`
|
||||||
|
//[next]~^^ ERROR conflicting implementations of trait `Overlap` for type `u32`
|
||||||
type Assoc = Box<usize>;
|
type Assoc = Box<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
tests/ui/traits/new-solver/tait-eq-proj-2.rs
Normal file
21
tests/ui/traits/new-solver/tait-eq-proj-2.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
// Similar to tests/ui/traits/new-solver/tait-eq-proj.rs
|
||||||
|
// but check the alias-sub relation in the other direction.
|
||||||
|
|
||||||
|
type Tait = impl Iterator<Item = impl Sized>;
|
||||||
|
|
||||||
|
fn mk<T>() -> T { todo!() }
|
||||||
|
|
||||||
|
fn a() {
|
||||||
|
let x: Tait = mk();
|
||||||
|
let mut array = mk();
|
||||||
|
let mut z = IntoIterator::into_iter(array);
|
||||||
|
z = x;
|
||||||
|
array = [0i32; 32];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
35
tests/ui/traits/new-solver/tait-eq-proj.rs
Normal file
35
tests/ui/traits/new-solver/tait-eq-proj.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
type Tait = impl Iterator<Item = impl Sized>;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Consider the goal - AliasRelate(Tait, <[i32; 32] as IntoIterator>::IntoIter)
|
||||||
|
which is registered on the line above.
|
||||||
|
|
||||||
|
A. SubstRelate - fails (of course).
|
||||||
|
|
||||||
|
B. NormalizesToRhs - Tait normalizes-to <[i32; 32] as IntoIterator>::IntoIter
|
||||||
|
* infer definition - Tait := <[i32; 32] as IntoIterator>::IntoIter
|
||||||
|
|
||||||
|
C. NormalizesToLhs - <[i32; 32] as IntoIterator>::IntoIter normalizes-to Tait
|
||||||
|
* Find impl candidate, after substitute - std::array::IntoIter<i32, 32>
|
||||||
|
* Equate std::array::IntoIter<i32, 32> and Tait
|
||||||
|
* infer definition - Tait := std::array::IntoIter<i32, 32>
|
||||||
|
|
||||||
|
B and C are not equal, but they are equivalent modulo normalization.
|
||||||
|
|
||||||
|
We get around this by evaluating both the NormalizesToRhs and NormalizesToLhs
|
||||||
|
goals together. Essentially:
|
||||||
|
A alias-relate B if A normalizes-to B and B normalizes-to A.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn a() {
|
||||||
|
let _: Tait = IntoIterator::into_iter([0i32; 32]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
17
tests/ui/traits/new-solver/tait-eq-tait.rs
Normal file
17
tests/ui/traits/new-solver/tait-eq-tait.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
// Not exactly sure if this is the inference behavior we *want*,
|
||||||
|
// but it is a side-effect of the lazy normalization of TAITs.
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
type Tait = impl Sized;
|
||||||
|
type Tait2 = impl Sized;
|
||||||
|
|
||||||
|
fn mk<T>() -> T { todo!() }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x: Tait = 1u32;
|
||||||
|
let y: Tait2 = x;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user