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:
commit
8996ea93b6
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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")];
|
||||
|
@ -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(") { "&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={}{}&edition={}">Run</a>"#,
|
||||
url, test_escaped, channel, edition,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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>'
|
||||
|
@ -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() {}
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
@ -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,) {}
|
||||
|
@ -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 {}
|
||||
|
@ -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>,
|
||||
|
@ -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() {}
|
106
tests/ui/modules/issue-107649.rs
Normal file
106
tests/ui/modules/issue-107649.rs
Normal 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`
|
||||
}
|
18
tests/ui/modules/issue-107649.stderr
Normal file
18
tests/ui/modules/issue-107649.stderr
Normal 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`.
|
@ -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() {}
|
12
tests/ui/traits/new-solver/elaborate-item-bounds.rs
Normal file
12
tests/ui/traits/new-solver/elaborate-item-bounds.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
|
||||
trait Foo {
|
||||
type Bar: Bar;
|
||||
}
|
||||
|
||||
trait Bar: Baz {}
|
||||
|
||||
trait Baz {}
|
||||
|
||||
fn main() {}
|
@ -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.
|
||||
|
@ -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`.
|
||||
|
22
tests/ui/traits/new-solver/temporary-ambiguity.rs
Normal file
22
tests/ui/traits/new-solver/temporary-ambiguity.rs
Normal 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);
|
||||
}
|
8
tests/ui/traits/new-solver/unsafe-auto-trait-impl.rs
Normal file
8
tests/ui/traits/new-solver/unsafe-auto-trait-impl.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
|
||||
struct Foo(*mut ());
|
||||
|
||||
unsafe impl Sync for Foo {}
|
||||
|
||||
fn main() {}
|
Loading…
x
Reference in New Issue
Block a user