Auto merge of #107853 - Dylan-DPC:rollup-macf1qo, r=Dylan-DPC

Rollup of 6 pull requests

Successful merges:

 - #107648 (unused-lifetimes: don't warn about lifetimes originating from expanded code)
 - #107655 (rustdoc: use the same URL escape rules for fragments as for examples)
 - #107659 (test: snapshot for derive suggestion in diff files)
 - #107786 (Implement some tweaks in the new solver)
 - #107803 (Do not bring trait alias supertraits into scope)
 - #107815 (Disqualify `auto trait` built-in impl in new solver if explicit `impl` exists)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-02-09 20:23:00 +00:00
commit 8996ea93b6
25 changed files with 437 additions and 265 deletions

View File

@ -1796,17 +1796,17 @@ impl EmitterWriter {
// telling users to make a change but not clarifying *where*.
let loc = sm.lookup_char_pos(parts[0].span.lo());
if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() {
buffer.puts(row_num - 1, 0, "--> ", Style::LineNumber);
buffer.append(
row_num - 1,
&format!(
"{}:{}:{}",
sm.filename_for_diagnostics(&loc.file.name),
sm.doctest_offset_line(&loc.file.name, loc.line),
loc.col.0 + 1,
),
Style::LineAndColumn,
);
let arrow = "--> ";
buffer.puts(row_num - 1, 0, arrow, Style::LineNumber);
let filename = sm.filename_for_diagnostics(&loc.file.name);
let offset = sm.doctest_offset_line(&loc.file.name, loc.line);
let message = format!("{}:{}:{}", filename, offset, loc.col.0 + 1);
if row_num == 2 {
let col = usize::max(max_line_num_len + 1, arrow.len());
buffer.puts(1, col, &message, Style::LineAndColumn);
} else {
buffer.append(row_num - 1, &message, Style::LineAndColumn);
}
for _ in 0..max_line_num_len {
buffer.prepend(row_num - 1, " ", Style::NoStyle);
}

View File

@ -951,24 +951,38 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let trait_ref = self.tcx.mk_trait_ref(trait_def_id, trait_substs);
if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, assume all supertraits are relevant.
let bounds = iter::once(ty::Binder::dummy(trait_ref));
self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
// For trait aliases, recursively assume all explicitly named traits are relevant
for expansion in traits::expand_trait_aliases(
self.tcx,
iter::once((ty::Binder::dummy(trait_ref), self.span)),
) {
let bound_trait_ref = expansion.trait_ref();
for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
if !self.has_applicable_self(&item) {
self.record_static_candidate(CandidateSource::Trait(
bound_trait_ref.def_id(),
));
} else {
let new_trait_ref = self.erase_late_bound_regions(bound_trait_ref);
let (xform_self_ty, xform_ret_ty) =
this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
this.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
import_ids: import_ids.clone(),
kind: TraitCandidate(new_trait_ref),
},
false,
);
});
let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(
&item,
new_trait_ref.self_ty(),
new_trait_ref.substs,
);
self.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
import_ids: import_ids.clone(),
kind: TraitCandidate(new_trait_ref),
},
false,
);
}
}
}
} else {
debug_assert!(self.tcx.is_trait(trait_def_id));
if self.tcx.trait_is_auto(trait_def_id) {

View File

@ -2244,19 +2244,23 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
None => {
debug!(?param.ident, ?param.ident.span);
let deletion_span = deletion_span();
self.r.lint_buffer.buffer_lint_with_diagnostic(
lint::builtin::UNUSED_LIFETIMES,
param.id,
param.ident.span,
&format!("lifetime parameter `{}` never used", param.ident),
lint::BuiltinLintDiagnostics::SingleUseLifetime {
param_span: param.ident.span,
use_span: None,
deletion_span,
},
);
// the give lifetime originates from expanded code so we won't be able to remove it #104432
let lifetime_only_in_expanded_code =
deletion_span.map(|sp| sp.in_derive_expansion()).unwrap_or(true);
if !lifetime_only_in_expanded_code {
self.r.lint_buffer.buffer_lint_with_diagnostic(
lint::builtin::UNUSED_LIFETIMES,
param.id,
param.ident.span,
&format!("lifetime parameter `{}` never used", param.ident),
lint::BuiltinLintDiagnostics::SingleUseLifetime {
param_span: param.ident.span,
use_span: None,
deletion_span,
},
);
}
}
}
}

View File

@ -3,7 +3,7 @@
use super::infcx_ext::InferCtxtExt;
#[cfg(doc)]
use super::trait_goals::structural_traits::*;
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::elaborate_predicates;
@ -399,10 +399,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
ty::Alias(_, alias_ty) => alias_ty,
};
for (assumption, _) in self
.tcx()
.bound_explicit_item_bounds(alias_ty.def_id)
.subst_iter_copied(self.tcx(), alias_ty.substs)
for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
{
match G::consider_assumption(self, goal, assumption) {
Ok(result) => {
@ -462,4 +459,78 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
}
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_candidates_and_discard_reservation_impls(
&mut self,
mut candidates: Vec<Candidate<'tcx>>,
) -> QueryResult<'tcx> {
match candidates.len() {
0 => return Err(NoSolution),
1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
_ => {}
}
if candidates.len() > 1 {
let mut i = 0;
'outer: while i < candidates.len() {
for j in (0..candidates.len()).filter(|&j| i != j) {
if self.trait_candidate_should_be_dropped_in_favor_of(
&candidates[i],
&candidates[j],
) {
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
candidates.swap_remove(i);
continue 'outer;
}
}
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
i += 1;
}
// If there are *STILL* multiple candidates, give up
// and report ambiguity.
if candidates.len() > 1 {
let certainty = if candidates.iter().all(|x| {
matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow))
}) {
Certainty::Maybe(MaybeCause::Overflow)
} else {
Certainty::AMBIGUOUS
};
return self.make_canonical_response(certainty);
}
}
Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
}
fn trait_candidate_should_be_dropped_in_favor_of(
&self,
candidate: &Candidate<'tcx>,
other: &Candidate<'tcx>,
) -> bool {
// FIXME: implement this
match (candidate.source, other.source) {
(CandidateSource::Impl(_), _)
| (CandidateSource::ParamEnv(_), _)
| (CandidateSource::AliasBound, _)
| (CandidateSource::BuiltinImpl, _) => false,
}
}
fn discard_reservation_impl(&self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
if let CandidateSource::Impl(def_id) = candidate.source {
if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
debug!("Selected reservation impl");
// We assemble all candidates inside of a probe so by
// making a new canonical response here our result will
// have no constraints.
candidate.result = self.make_canonical_response(Certainty::AMBIGUOUS).unwrap();
}
}
candidate
}
}

View File

@ -1,6 +1,6 @@
use crate::traits::{specialization_graph, translate_substs};
use super::assembly::{self, Candidate, CandidateSource};
use super::assembly;
use super::infcx_ext::InferCtxtExt;
use super::trait_goals::structural_traits;
use super::{Certainty, EvalCtxt, Goal, QueryResult};
@ -34,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// projection cache in the solver.
if self.term_is_fully_unconstrained(goal) {
let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_project_candidates(candidates)
self.merge_candidates_and_discard_reservation_impls(candidates)
} else {
let predicate = goal.predicate;
let unconstrained_rhs = match predicate.term.unpack() {
@ -153,59 +153,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.make_canonical_response(normalization_certainty.unify_and(rhs_certainty))
}
fn merge_project_candidates(
&mut self,
mut candidates: Vec<Candidate<'tcx>>,
) -> QueryResult<'tcx> {
match candidates.len() {
0 => return Err(NoSolution),
1 => return Ok(candidates.pop().unwrap().result),
_ => {}
}
if candidates.len() > 1 {
let mut i = 0;
'outer: while i < candidates.len() {
for j in (0..candidates.len()).filter(|&j| i != j) {
if self.project_candidate_should_be_dropped_in_favor_of(
&candidates[i],
&candidates[j],
) {
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
candidates.swap_remove(i);
continue 'outer;
}
}
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
// If there are *STILL* multiple candidates, give up
// and report ambiguity.
i += 1;
if i > 1 {
debug!("multiple matches, ambig");
// FIXME: return overflow if all candidates overflow, otherwise return ambiguity.
unimplemented!();
}
}
}
Ok(candidates.pop().unwrap().result)
}
fn project_candidate_should_be_dropped_in_favor_of(
&self,
candidate: &Candidate<'tcx>,
other: &Candidate<'tcx>,
) -> bool {
// FIXME: implement this
match (candidate.source, other.source) {
(CandidateSource::Impl(_), _)
| (CandidateSource::ParamEnv(_), _)
| (CandidateSource::BuiltinImpl, _)
| (CandidateSource::AliasBound, _) => unimplemented!(),
}
}
}
impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
@ -452,7 +399,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
[ty::GenericArg::from(goal.predicate.self_ty())],
));
let is_sized_certainty = ecx.evaluate_goal(goal.with(tcx, sized_predicate))?.1;
let (_, is_sized_certainty) =
ecx.evaluate_goal(goal.with(tcx, sized_predicate))?;
return ecx.eq_term_and_make_canonical_response(
goal,
is_sized_certainty,

View File

@ -2,7 +2,7 @@
use std::iter;
use super::assembly::{self, Candidate, CandidateSource};
use super::assembly;
use super::infcx_ext::InferCtxtExt;
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
use rustc_hir::def_id::DefId;
@ -89,6 +89,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
// This differs from the current stable behavior and
// fixes #84857. Due to breakage found via crater, we
// currently instead lint patterns which can be used to
// exploit this unsoundness on stable, see #93367 for
// more details.
if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
goal.predicate.def_id(),
goal.predicate.self_ty(),
Some,
) {
debug!(?def_id, ?goal, "disqualified auto-trait implementation");
return Err(NoSolution);
}
ecx.probe_and_evaluate_goal_for_constituent_tys(
goal,
structural_traits::instantiate_constituent_tys_for_auto_trait,
@ -479,73 +493,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
goal: Goal<'tcx, TraitPredicate<'tcx>>,
) -> QueryResult<'tcx> {
let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_trait_candidates_discard_reservation_impls(candidates)
}
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_trait_candidates_discard_reservation_impls(
&mut self,
mut candidates: Vec<Candidate<'tcx>>,
) -> QueryResult<'tcx> {
match candidates.len() {
0 => return Err(NoSolution),
1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
_ => {}
}
if candidates.len() > 1 {
let mut i = 0;
'outer: while i < candidates.len() {
for j in (0..candidates.len()).filter(|&j| i != j) {
if self.trait_candidate_should_be_dropped_in_favor_of(
&candidates[i],
&candidates[j],
) {
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
candidates.swap_remove(i);
continue 'outer;
}
}
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
// If there are *STILL* multiple candidates, give up
// and report ambiguity.
i += 1;
if i > 1 {
debug!("multiple matches, ambig");
// FIXME: return overflow if all candidates overflow, otherwise return ambiguity.
unimplemented!();
}
}
}
Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
}
fn trait_candidate_should_be_dropped_in_favor_of(
&self,
candidate: &Candidate<'tcx>,
other: &Candidate<'tcx>,
) -> bool {
// FIXME: implement this
match (candidate.source, other.source) {
(CandidateSource::Impl(_), _)
| (CandidateSource::ParamEnv(_), _)
| (CandidateSource::AliasBound, _)
| (CandidateSource::BuiltinImpl, _) => unimplemented!(),
}
}
fn discard_reservation_impl(&self, candidate: Candidate<'tcx>) -> Candidate<'tcx> {
if let CandidateSource::Impl(def_id) = candidate.source {
if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
debug!("Selected reservation impl");
// FIXME: reduce candidate to ambiguous
// FIXME: replace `var_values` with identity, yeet external constraints.
unimplemented!()
}
}
candidate
self.merge_candidates_and_discard_reservation_impls(candidates)
}
}

View File

@ -646,11 +646,9 @@ fn object_ty_for_trait<'tcx>(
debug!(?obligation);
let pred = obligation.predicate.to_opt_poly_projection_pred()?;
Some(pred.map_bound(|p| {
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
def_id: p.projection_ty.def_id,
substs: p.projection_ty.substs,
term: p.term,
})
ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
tcx, p,
))
}))
})
.collect();

View File

@ -458,7 +458,7 @@
//! [`Result`] of a collection of each contained value of the original
//! [`Result`] values, or [`Err`] if any of the elements was [`Err`].
//!
//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E-for-Result%3CV%2C%20E%3E
//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA,+E%3E%3E-for-Result%3CV,+E%3E
//!
//! ```
//! let v = [Ok(2), Ok(4), Err("err!"), Ok(8)];
@ -474,8 +474,8 @@
//! to provide the [`product`][Iterator::product] and
//! [`sum`][Iterator::sum] methods.
//!
//! [impl-Product]: Result#impl-Product%3CResult%3CU%2C%20E%3E%3E-for-Result%3CT%2C%20E%3E
//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E-for-Result%3CT%2C%20E%3E
//! [impl-Product]: Result#impl-Product%3CResult%3CU,+E%3E%3E-for-Result%3CT,+E%3E
//! [impl-Sum]: Result#impl-Sum%3CResult%3CU,+E%3E%3E-for-Result%3CT,+E%3E
//!
//! ```
//! let v = [Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")];

View File

@ -46,6 +46,7 @@ use crate::html::escape::Escape;
use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::length_limit::HtmlWithLimit;
use crate::html::render::small_url_encode;
use crate::html::toc::TocBuilder;
use pulldown_cmark::{
@ -294,47 +295,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
doctest::make_test(&test, krate, false, &Default::default(), edition, None);
let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
// These characters don't need to be escaped in a URI.
// See https://url.spec.whatwg.org/#query-percent-encode-set
// and https://url.spec.whatwg.org/#urlencoded-parsing
// and https://url.spec.whatwg.org/#url-code-points
fn dont_escape(c: u8) -> bool {
(b'a' <= c && c <= b'z')
|| (b'A' <= c && c <= b'Z')
|| (b'0' <= c && c <= b'9')
|| c == b'-'
|| c == b'_'
|| c == b'.'
|| c == b','
|| c == b'~'
|| c == b'!'
|| c == b'\''
|| c == b'('
|| c == b')'
|| c == b'*'
|| c == b'/'
|| c == b';'
|| c == b':'
|| c == b'?'
// As described in urlencoded-parsing, the
// first `=` is the one that separates key from
// value. Following `=`s are part of the value.
|| c == b'='
}
let mut test_escaped = String::new();
for b in test.bytes() {
if dont_escape(b) {
test_escaped.push(char::from(b));
} else if b == b' ' {
// URL queries are decoded with + replaced with SP
test_escaped.push('+');
} else if b == b'%' {
test_escaped.push('%');
test_escaped.push('%');
} else {
write!(test_escaped, "%{:02X}", b).unwrap();
}
}
let test_escaped = small_url_encode(test);
Some(format!(
r#"<a class="test-arrow" target="_blank" href="{}?code={}{}&amp;edition={}">Run</a>"#,
url, test_escaped, channel, edition,

View File

@ -38,7 +38,7 @@ pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
use std::collections::VecDeque;
use std::default::Default;
use std::fmt;
use std::fmt::{self, Write};
use std::fs;
use std::iter::Peekable;
use std::path::PathBuf;
@ -2020,31 +2020,60 @@ fn get_associated_constants(
.collect::<Vec<_>>()
}
// The point is to url encode any potential character from a type with genericity.
fn small_url_encode(s: String) -> String {
pub(crate) fn small_url_encode(s: String) -> String {
// These characters don't need to be escaped in a URI.
// See https://url.spec.whatwg.org/#query-percent-encode-set
// and https://url.spec.whatwg.org/#urlencoded-parsing
// and https://url.spec.whatwg.org/#url-code-points
fn dont_escape(c: u8) -> bool {
(b'a' <= c && c <= b'z')
|| (b'A' <= c && c <= b'Z')
|| (b'0' <= c && c <= b'9')
|| c == b'-'
|| c == b'_'
|| c == b'.'
|| c == b','
|| c == b'~'
|| c == b'!'
|| c == b'\''
|| c == b'('
|| c == b')'
|| c == b'*'
|| c == b'/'
|| c == b';'
|| c == b':'
|| c == b'?'
// As described in urlencoded-parsing, the
// first `=` is the one that separates key from
// value. Following `=`s are part of the value.
|| c == b'='
}
let mut st = String::new();
let mut last_match = 0;
for (idx, c) in s.char_indices() {
let escaped = match c {
'<' => "%3C",
'>' => "%3E",
' ' => "%20",
'?' => "%3F",
'\'' => "%27",
'&' => "%26",
',' => "%2C",
':' => "%3A",
';' => "%3B",
'[' => "%5B",
']' => "%5D",
'"' => "%22",
_ => continue,
};
for (idx, b) in s.bytes().enumerate() {
if dont_escape(b) {
continue;
}
st += &s[last_match..idx];
st += escaped;
// NOTE: we only expect single byte characters here - which is fine as long as we
// only match single byte characters
if last_match != idx {
// Invariant: `idx` must be the first byte in a character at this point.
st += &s[last_match..idx];
}
if b == b' ' {
// URL queries are decoded with + replaced with SP.
// While the same is not true for hashes, rustdoc only needs to be
// consistent with itself when encoding them.
st += "+";
} else if b == b'%' {
st += "%%";
} else {
write!(st, "%{:02X}", b).unwrap();
}
// Invariant: if the current byte is not at the start of a multi-byte character,
// we need to get down here so that when the next turn of the loop comes around,
// last_match winds up equalling idx.
//
// In other words, dont_escape must always return `false` in multi-byte character.
last_match = idx + 1;
}

View File

@ -21,8 +21,8 @@ pub use extern_crate::WTrait;
// 'pub trait Trait<const N: usize>'
// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<1> for u8'
// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<2> for u8'
// @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<{1 + 2}> for u8'
// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//h3[@class="code-header"]' \
// @has - '//*[@id="impl-Trait%3C%7B1+%2B+2%7D%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<{1 + 2}> for u8'
// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8;+N%5D"]//h3[@class="code-header"]' \
// 'impl<const N: usize> Trait<N> for [u8; N]'
pub trait Trait<const N: usize> {}
impl Trait<1> for u8 {}
@ -47,7 +47,7 @@ impl<const M: usize> Foo<M> where u8: Trait<M> {
}
}
// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Bar<u8, M>'
// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8,+M%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Bar<u8, M>'
impl<const M: usize> Bar<u8, M> {
// @has - '//*[@id="method.hey"]' \
// 'pub fn hey<const N: usize>(&self) -> Foo<N>where u8: Trait<N>'

View File

@ -9,20 +9,20 @@ pub enum Order {
}
// @has foo/struct.VSet.html '//pre[@class="rust item-decl"]' 'pub struct VSet<T, const ORDER: Order>'
// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT,+ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT,+ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
pub struct VSet<T, const ORDER: Order> {
inner: Vec<T>,
}
// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3ASorted%20}%3E"]/h3[@class="code-header"]' 'impl<T> VSet<T, { Order::Sorted }>'
// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT,+%7B+Order::Sorted+%7D%3E"]/h3[@class="code-header"]' 'impl<T> VSet<T, { Order::Sorted }>'
impl<T> VSet<T, { Order::Sorted }> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
}
// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3AUnsorted%20}%3E"]/h3[@class="code-header"]' 'impl<T> VSet<T, { Order::Unsorted }>'
// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT,+%7B+Order::Unsorted+%7D%3E"]/h3[@class="code-header"]' 'impl<T> VSet<T, { Order::Unsorted }>'
impl<T> VSet<T, { Order::Unsorted }> {
pub fn new() -> Self {
Self { inner: Vec::new() }
@ -31,7 +31,7 @@ impl<T> VSet<T, { Order::Unsorted }> {
pub struct Escape<const S: &'static str>;
// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr#%22%3Cscript%3Ealert(%22Escape%22)%3B%3C/script%3E%22#%3E"]/h3[@class="code-header"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr%23%22%3Cscript%3Ealert(%22Escape%22);%3C/script%3E%22%23%3E"]/h3[@class="code-header"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
impl Escape<r#"<script>alert("Escape");</script>"#> {
pub fn f() {}
}

View File

@ -7,5 +7,5 @@ pub trait Foo<T> {
pub struct Bar;
// @has foo/struct.Bar.html
// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E-for-Bar"]' 'Foo<unsafe extern "C" fn()>'
// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe+extern+%22C%22+fn()%3E-for-Bar"]' 'Foo<unsafe extern "C" fn()>'
impl Foo<unsafe extern "C" fn()> for Bar {}

View File

@ -6,13 +6,13 @@
pub trait Foo {}
// @has foo/trait.Foo.html
// @has - '//section[@id="impl-Foo-for-(T%2C)"]/h3' 'impl<T> Foo for (T₁, T₂, …, Tₙ)'
// @has - '//section[@id="impl-Foo-for-(T,)"]/h3' 'impl<T> Foo for (T₁, T₂, …, Tₙ)'
#[doc(fake_variadic)]
impl<T> Foo for (T,) {}
pub trait Bar {}
// @has foo/trait.Bar.html
// @has - '//section[@id="impl-Bar-for-(U%2C)"]/h3' 'impl<U: Foo> Bar for (U₁, U₂, …, Uₙ)'
// @has - '//section[@id="impl-Bar-for-(U,)"]/h3' 'impl<U: Foo> Bar for (U₁, U₂, …, Uₙ)'
#[doc(fake_variadic)]
impl<U: Foo> Bar for (U,) {}

View File

@ -7,8 +7,8 @@
// @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32'
// @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header"]' 'impl Foo for u32'
// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
// @has - '//*[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header"]' "impl<'a> Foo for &'a str"
// @has - "//*[@class=\"sidebar-elems\"]//section//a[@href=\"#impl-Foo-for-%26'a+str\"]" "&'a str"
// @has - "//*[@id=\"impl-Foo-for-%26'a+str\"]//h3[@class=\"code-header\"]" "impl<'a> Foo for &'a str"
pub trait Foo {}
impl Foo for u32 {}

View File

@ -7,7 +7,7 @@ where
}
// @has 'foo/trait.SomeTrait.html'
// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
// @has - "//*[@id='impl-SomeTrait%3C(A,+B,+C,+D,+E)%3E-for-(A,+B,+C,+D,+E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)
where
A: PartialOrd<A> + PartialEq<A>,

View File

@ -0,0 +1,12 @@
// check-pass
#![deny(unused_lifetimes)]
trait Trait2 {
type As;
}
// we should not warn about an unused lifetime about code generated from this proc macro here
#[derive(Clone)]
struct ShimMethod4<T: Trait2 + 'static>(pub &'static dyn for<'s> Fn(&'s mut T::As));
pub fn main() {}

View File

@ -0,0 +1,106 @@
// compile-flags: -Z ui-testing=no
#[path = "auxiliary/dummy_lib.rs"]
mod lib;
/// The function needs to be long enough to
/// ensure `max_line_num_len` to be large enough
/// for no-ui-testing
fn main() {
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
();
dbg!(lib::Dummy); //~ Error: `Dummy` doesn't implement `Debug`
}

View File

@ -0,0 +1,18 @@
error[E0277]: `Dummy` doesn't implement `Debug`
--> $DIR/issue-107649.rs:105:5
|
105 | dbg!(lib::Dummy);
| ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Dummy`
= note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy`
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Dummy` with `#[derive(Debug)]`
--> $DIR/auxiliary/dummy_lib.rs:2:1
|
2 | #[derive(Debug)]
|
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,21 @@
// Regression test for #107747: methods from trait alias supertraits were brought into scope
//
// check-pass
#![feature(trait_alias)]
use std::fmt;
trait Foo: fmt::Debug {}
trait Bar = Foo;
#[derive(Debug)]
struct Qux(bool);
impl fmt::Display for Qux {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
fn main() {}

View File

@ -0,0 +1,12 @@
// compile-flags: -Ztrait-solver=next
// check-pass
trait Foo {
type Bar: Bar;
}
trait Bar: Baz {}
trait Baz {}
fn main() {}

View File

@ -1,9 +1,5 @@
// known-bug: unknown
// compile-flags: -Ztrait-solver=next
// failure-status: 101
// normalize-stderr-test "note: .*\n\n" -> ""
// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
// rustc-env:RUST_BACKTRACE=0
// This tests checks that we update results in the provisional cache when
// we pop a goal from the stack.

View File

@ -1,6 +1,11 @@
error: the compiler unexpectedly panicked. this is a bug.
error[E0283]: type annotations needed: cannot satisfy `Bar<T>: Coinductive`
--> $DIR/provisional-result-done.rs:16:25
|
LL | impl<T> Coinductive for Bar<T>
| ^^^^^^
|
= note: cannot satisfy `Bar<T>: Coinductive`
query stack during panic:
#0 [check_well_formed] checking that `<impl at $DIR/provisional-result-done.rs:20:1: 20:31>` is well-formed
#1 [check_mod_type_wf] checking that types are well-formed in top-level module
end of query stack
error: aborting due to previous error
For more information about this error, try `rustc --explain E0283`.

View File

@ -0,0 +1,22 @@
// compile-flags: -Ztrait-solver=next
// check-pass
// Checks that we don't explode when we assemble >1 candidate for a goal.
struct Wrapper<T>(T);
trait Foo {}
impl Foo for Wrapper<i32> {}
impl Foo for Wrapper<()> {}
fn needs_foo(_: impl Foo) {}
fn main() {
let mut x = Default::default();
let w = Wrapper(x);
needs_foo(w);
x = 1;
drop(x);
}

View File

@ -0,0 +1,8 @@
// compile-flags: -Ztrait-solver=next
// check-pass
struct Foo(*mut ());
unsafe impl Sync for Foo {}
fn main() {}