1
Fork 0

Auto merge of #135713 - matthiaskrgr:rollup-c04uupz, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #135616 (CI: split i686-msvc job to two free runners)
 - #135623 (ci: use ghcr ubuntu image for mingw-check-tidy)
 - #135640 (Drop MIPS glibc 2.23 patches that reside in crosstool-ng now)
 - #135663 (Fix ICE in resolving associated items as non-bindings)
 - #135680 (coverage: Clean up a few things after the counters overhaul)
 - #135697 (Get rid of `ToPolyTraitRef`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-01-19 00:21:10 +00:00
commit 01706e1a34
32 changed files with 388 additions and 460 deletions

View file

@ -1,5 +1,5 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::{self, ToPolyTraitRef, TyCtxt};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{Ident, Span};
pub use rustc_type_ir::elaborate::*;
@ -125,8 +125,8 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
.iter_identity_copied()
.map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref))
.filter_map(|clause| clause.as_trait_clause())
// FIXME: Negative supertraits are elaborated here lol
.map(|trait_pred| trait_pred.to_poly_trait_ref()),
.filter(|clause| clause.polarity() == ty::PredicatePolarity::Positive)
.map(|clause| clause.map_bound(|clause| clause.trait_ref)),
);
return Some(trait_ref);

View file

@ -71,11 +71,7 @@ impl ConditionId {
/// Enum that can hold a constant zero value, the ID of an physical coverage
/// counter, or the ID of a coverage-counter expression.
///
/// This was originally only used for expression operands (and named `Operand`),
/// but the zero/counter/expression distinction is also useful for representing
/// the value of code/gap mappings, and the true/false arms of branch mappings.
#[derive(Copy, Clone, PartialEq, Eq)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum CovTerm {
Zero,
@ -171,7 +167,7 @@ impl Op {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct Expression {
pub lhs: CovTerm,

View file

@ -79,8 +79,7 @@ pub use self::predicate::{
PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef,
TypeOutlivesPredicate,
RegionOutlivesPredicate, SubtypePredicate, TraitPredicate, TraitRef, TypeOutlivesPredicate,
};
pub use self::region::{
BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region,

View file

@ -476,16 +476,6 @@ impl<'tcx> Clause<'tcx> {
}
}
pub trait ToPolyTraitRef<'tcx> {
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
}
impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PredicateKind<'tcx>> for Predicate<'tcx> {
fn upcast_from(from: PredicateKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
ty::Binder::dummy(from).upcast(tcx)

View file

@ -1,10 +1,9 @@
use std::cmp::Ordering;
use std::fmt::{self, Debug};
use either::Either;
use itertools::Itertools;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::graph::DirectedGraph;
use rustc_index::IndexVec;
use rustc_index::bit_set::DenseBitSet;
@ -20,76 +19,31 @@ mod iter_nodes;
mod node_flow;
mod union_find;
/// The coverage counter or counter expression associated with a particular
/// BCB node or BCB edge.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum BcbCounter {
Counter { id: CounterId },
Expression { id: ExpressionId },
}
impl BcbCounter {
fn as_term(&self) -> CovTerm {
match *self {
BcbCounter::Counter { id, .. } => CovTerm::Counter(id),
BcbCounter::Expression { id, .. } => CovTerm::Expression(id),
}
}
}
impl Debug for BcbCounter {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
Self::Expression { id } => write!(fmt, "Expression({:?})", id.index()),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct BcbExpression {
lhs: BcbCounter,
op: Op,
rhs: BcbCounter,
}
/// Enum representing either a node or an edge in the coverage graph.
///
/// FIXME(#135481): This enum is no longer needed now that we only instrument
/// nodes and not edges. It can be removed in a subsequent PR.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(super) enum Site {
Node { bcb: BasicCoverageBlock },
}
/// Generates and stores coverage counter and coverage expression information
/// associated with nodes/edges in the BCB graph.
pub(super) struct CoverageCounters {
/// List of places where a counter-increment statement should be injected
/// into MIR, each with its corresponding counter ID.
counter_increment_sites: IndexVec<CounterId, Site>,
/// Coverage counters/expressions that are associated with individual BCBs.
node_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
/// Table of expression data, associating each expression ID with its
/// corresponding operator (+ or -) and its LHS/RHS operands.
expressions: IndexVec<ExpressionId, BcbExpression>,
/// Remember expressions that have already been created (or simplified),
/// so that we don't create unnecessary duplicates.
expressions_memo: FxHashMap<BcbExpression, BcbCounter>,
}
impl CoverageCounters {
/// Ensures that each BCB node needing a counter has one, by creating physical
/// counters or counter expressions for nodes and edges as required.
pub(super) fn make_bcb_counters(
/// Ensures that each BCB node needing a counter has one, by creating physical
/// counters or counter expressions for nodes as required.
pub(super) fn make_bcb_counters(
graph: &CoverageGraph,
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
) -> Self {
) -> CoverageCounters {
// Create the derived graphs that are necessary for subsequent steps.
let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph);
// Use those graphs to determine which nodes get physical counters, and how
// to compute the execution counts of other nodes from those counters.
let nodes = make_node_counter_priority_list(graph, balanced_graph);
let node_counters = merged_graph.make_node_counters(&nodes);
// Convert the counters into a form suitable for embedding into MIR.
transcribe_counters(&node_counters, bcb_needs_counter)
}
/// Arranges the nodes in `balanced_graph` into a list, such that earlier nodes
/// take priority in being given a counter expression instead of a physical counter.
fn make_node_counter_priority_list(
graph: &CoverageGraph,
balanced_graph: BalancedFlowGraph<&CoverageGraph>,
) -> Vec<BasicCoverageBlock> {
// A "reloop" node has exactly one out-edge, which jumps back to the top
// of an enclosing loop. Reloop nodes are typically visited more times
// than loop-exit nodes, so try to avoid giving them physical counters.
@ -116,38 +70,112 @@ impl CoverageCounters {
// Otherwise, prefer a physical counter for dominating nodes.
.then_with(|| graph.cmp_in_dominator_order(a, b).reverse())
});
let node_counters = merged_graph.make_node_counters(&nodes);
nodes
}
Transcriber::new(graph.num_nodes(), node_counters).transcribe_counters(bcb_needs_counter)
// Converts node counters into a form suitable for embedding into MIR.
fn transcribe_counters(
old: &NodeCounters<BasicCoverageBlock>,
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
) -> CoverageCounters {
let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size());
for bcb in bcb_needs_counter.iter() {
// Our counter-creation algorithm doesn't guarantee that a counter
// expression starts or ends with a positive term, so partition the
// counters into "positive" and "negative" lists for easier handling.
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
old.counter_expr(bcb).iter().partition_map(|&CounterTerm { node, op }| match op {
Op::Add => Either::Left(node),
Op::Subtract => Either::Right(node),
});
if pos.is_empty() {
// If we somehow end up with no positive terms, fall back to
// creating a physical counter. There's no known way for this
// to happen, but we can avoid an ICE if it does.
debug_assert!(false, "{bcb:?} has no positive counter terms");
pos = vec![bcb];
neg = vec![];
}
// These intermediate sorts are not strictly necessary, but were helpful
// in reducing churn when switching to the current counter-creation scheme.
// They also help to slightly decrease the overall size of the expression
// table, due to more subexpressions being shared.
pos.sort();
neg.sort();
let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| {
sites.into_iter().map(|node| new.ensure_phys_counter(node)).collect::<Vec<_>>()
};
let mut pos = new_counters_for_sites(pos);
let mut neg = new_counters_for_sites(neg);
// These sorts are also not strictly necessary; see above.
pos.sort();
neg.sort();
let pos_counter = new.make_sum(&pos).expect("`pos` should not be empty");
let new_counter = new.make_subtracted_sum(pos_counter, &neg);
new.set_node_counter(bcb, new_counter);
}
new
}
/// Generates and stores coverage counter and coverage expression information
/// associated with nodes in the coverage graph.
pub(super) struct CoverageCounters {
/// List of places where a counter-increment statement should be injected
/// into MIR, each with its corresponding counter ID.
phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>,
next_counter_id: CounterId,
/// Coverage counters/expressions that are associated with individual BCBs.
node_counters: IndexVec<BasicCoverageBlock, Option<CovTerm>>,
/// Table of expression data, associating each expression ID with its
/// corresponding operator (+ or -) and its LHS/RHS operands.
expressions: IndexVec<ExpressionId, Expression>,
/// Remember expressions that have already been created (or simplified),
/// so that we don't create unnecessary duplicates.
expressions_memo: FxHashMap<Expression, CovTerm>,
}
impl CoverageCounters {
fn with_num_bcbs(num_bcbs: usize) -> Self {
Self {
counter_increment_sites: IndexVec::new(),
phys_counter_for_node: FxIndexMap::default(),
next_counter_id: CounterId::ZERO,
node_counters: IndexVec::from_elem_n(None, num_bcbs),
expressions: IndexVec::new(),
expressions_memo: FxHashMap::default(),
}
}
/// Creates a new physical counter for a BCB node or edge.
fn make_phys_counter(&mut self, site: Site) -> BcbCounter {
let id = self.counter_increment_sites.push(site);
BcbCounter::Counter { id }
/// Returns the physical counter for the given node, creating it if necessary.
fn ensure_phys_counter(&mut self, bcb: BasicCoverageBlock) -> CovTerm {
let id = *self.phys_counter_for_node.entry(bcb).or_insert_with(|| {
let id = self.next_counter_id;
self.next_counter_id = id + 1;
id
});
CovTerm::Counter(id)
}
fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
let new_expr = BcbExpression { lhs, op, rhs };
*self.expressions_memo.entry(new_expr).or_insert_with(|| {
fn make_expression(&mut self, lhs: CovTerm, op: Op, rhs: CovTerm) -> CovTerm {
let new_expr = Expression { lhs, op, rhs };
*self.expressions_memo.entry(new_expr.clone()).or_insert_with(|| {
let id = self.expressions.push(new_expr);
BcbCounter::Expression { id }
CovTerm::Expression(id)
})
}
/// Creates a counter that is the sum of the given counters.
///
/// Returns `None` if the given list of counters was empty.
fn make_sum(&mut self, counters: &[BcbCounter]) -> Option<BcbCounter> {
fn make_sum(&mut self, counters: &[CovTerm]) -> Option<CovTerm> {
counters
.iter()
.copied()
@ -155,16 +183,18 @@ impl CoverageCounters {
}
/// Creates a counter whose value is `lhs - SUM(rhs)`.
fn make_subtracted_sum(&mut self, lhs: BcbCounter, rhs: &[BcbCounter]) -> BcbCounter {
fn make_subtracted_sum(&mut self, lhs: CovTerm, rhs: &[CovTerm]) -> CovTerm {
let Some(rhs_sum) = self.make_sum(rhs) else { return lhs };
self.make_expression(lhs, Op::Subtract, rhs_sum)
}
pub(super) fn num_counters(&self) -> usize {
self.counter_increment_sites.len()
let num_counters = self.phys_counter_for_node.len();
assert_eq!(num_counters, self.next_counter_id.as_usize());
num_counters
}
fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: BcbCounter) -> BcbCounter {
fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: CovTerm) -> CovTerm {
let existing = self.node_counters[bcb].replace(counter);
assert!(
existing.is_none(),
@ -174,16 +204,16 @@ impl CoverageCounters {
}
pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> {
self.node_counters[bcb].map(|counter| counter.as_term())
self.node_counters[bcb]
}
/// Returns an iterator over all the nodes/edges in the coverage graph that
/// Returns an iterator over all the nodes in the coverage graph that
/// should have a counter-increment statement injected into MIR, along with
/// each site's corresponding counter ID.
pub(super) fn counter_increment_sites(
&self,
) -> impl Iterator<Item = (CounterId, Site)> + Captures<'_> {
self.counter_increment_sites.iter_enumerated().map(|(id, &site)| (id, site))
) -> impl Iterator<Item = (CounterId, BasicCoverageBlock)> + Captures<'_> {
self.phys_counter_for_node.iter().map(|(&site, &id)| (id, site))
}
/// Returns an iterator over the subset of BCB nodes that have been associated
@ -193,93 +223,13 @@ impl CoverageCounters {
) -> impl Iterator<Item = (BasicCoverageBlock, ExpressionId)> + Captures<'_> {
self.node_counters.iter_enumerated().filter_map(|(bcb, &counter)| match counter {
// Yield the BCB along with its associated expression ID.
Some(BcbCounter::Expression { id }) => Some((bcb, id)),
Some(CovTerm::Expression(id)) => Some((bcb, id)),
// This BCB is associated with a counter or nothing, so skip it.
Some(BcbCounter::Counter { .. }) | None => None,
Some(CovTerm::Counter { .. } | CovTerm::Zero) | None => None,
})
}
pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
let old_len = self.expressions.len();
let expressions = self
.expressions
.into_iter()
.map(|BcbExpression { lhs, op, rhs }| Expression {
lhs: lhs.as_term(),
op,
rhs: rhs.as_term(),
})
.collect::<IndexVec<ExpressionId, _>>();
// Expression IDs are indexes into this vector, so make sure we didn't
// accidentally invalidate them by changing its length.
assert_eq!(old_len, expressions.len());
expressions
}
}
struct Transcriber {
old: NodeCounters<BasicCoverageBlock>,
new: CoverageCounters,
phys_counter_for_site: FxHashMap<Site, BcbCounter>,
}
impl Transcriber {
fn new(num_nodes: usize, old: NodeCounters<BasicCoverageBlock>) -> Self {
Self {
old,
new: CoverageCounters::with_num_bcbs(num_nodes),
phys_counter_for_site: FxHashMap::default(),
}
}
fn transcribe_counters(
mut self,
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
) -> CoverageCounters {
for bcb in bcb_needs_counter.iter() {
let site = Site::Node { bcb };
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
self.old.counter_expr(bcb).iter().partition_map(
|&CounterTerm { node, op }| match op {
Op::Add => Either::Left(node),
Op::Subtract => Either::Right(node),
},
);
if pos.is_empty() {
// If we somehow end up with no positive terms, fall back to
// creating a physical counter. There's no known way for this
// to happen, but we can avoid an ICE if it does.
debug_assert!(false, "{site:?} has no positive counter terms");
pos = vec![bcb];
neg = vec![];
}
pos.sort();
neg.sort();
let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| {
sites
.into_iter()
.map(|node| self.ensure_phys_counter(Site::Node { bcb: node }))
.collect::<Vec<_>>()
};
let mut pos = new_counters_for_sites(pos);
let mut neg = new_counters_for_sites(neg);
pos.sort();
neg.sort();
let pos_counter = self.new.make_sum(&pos).expect("`pos` should not be empty");
let new_counter = self.new.make_subtracted_sum(pos_counter, &neg);
self.new.set_node_counter(bcb, new_counter);
}
self.new
}
fn ensure_phys_counter(&mut self, site: Site) -> BcbCounter {
*self.phys_counter_for_site.entry(site).or_insert_with(|| self.new.make_phys_counter(site))
self.expressions
}
}

View file

@ -21,7 +21,7 @@ use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
use tracing::{debug, debug_span, trace};
use crate::coverage::counters::{CoverageCounters, Site};
use crate::coverage::counters::CoverageCounters;
use crate::coverage::graph::CoverageGraph;
use crate::coverage::mappings::ExtractedMappings;
@ -89,8 +89,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
return;
}
let coverage_counters =
CoverageCounters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
let coverage_counters = counters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
let mappings = create_mappings(&extracted_mappings, &coverage_counters);
if mappings.is_empty() {
@ -239,14 +238,8 @@ fn inject_coverage_statements<'tcx>(
coverage_counters: &CoverageCounters,
) {
// Inject counter-increment statements into MIR.
for (id, site) in coverage_counters.counter_increment_sites() {
// Determine the block to inject a counter-increment statement into.
// For BCB nodes this is just their first block, but for edges we need
// to create a new block between the two BCBs, and inject into that.
let target_bb = match site {
Site::Node { bcb } => graph[bcb].leader_bb(),
};
for (id, bcb) in coverage_counters.counter_increment_sites() {
let target_bb = graph[bcb].leader_bb();
inject_statement(mir_body, CoverageKind::CounterIncrement { id }, target_bb);
}

View file

@ -3960,7 +3960,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
match res {
Res::SelfCtor(_) // See #70549.
| Res::Def(
DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::ConstParam,
DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst | DefKind::ConstParam,
_,
) if is_syntactic_ambiguity => {
// Disambiguate in favor of a unit struct/variant or constant pattern.
@ -3969,7 +3969,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
Some(res)
}
Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static { .. }, _) => {
Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::AssocConst | DefKind::Static { .. }, _) => {
// This is unambiguously a fresh binding, either syntactically
// (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
// to something unusable as a pattern (e.g., constructor function),
@ -4005,7 +4005,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
);
None
}
Res::Def(DefKind::Fn, _) | Res::Local(..) | Res::Err => {
Res::Def(DefKind::Fn | DefKind::AssocFn, _) | Res::Local(..) | Res::Err => {
// These entities are explicitly allowed to be shadowed by fresh bindings.
None
}

View file

@ -172,14 +172,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
let trait_ref = bound_predicate.rebind(data.trait_ref);
debug!(?trait_ref);
let trait_pred = bound_predicate.rebind(data);
debug!(?trait_pred);
if let Err(e) = predicate.error_reported() {
return e;
}
if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) {
if let Err(guar) = self.tcx.ensure().coherent_trait(trait_pred.def_id()) {
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
return guar;
@ -200,13 +200,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// avoid inundating the user with unnecessary errors, but we now
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) {
match self.tainted_by_errors() {
None => {
let err = self.emit_inference_failure_err(
obligation.cause.body_id,
span,
trait_ref.self_ty().skip_binder().into(),
trait_pred.self_ty().skip_binder().into(),
TypeAnnotationNeeded::E0282,
false,
);
@ -251,10 +251,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut ambiguities = compute_applicable_impls_for_diagnostics(
self.infcx,
&obligation.with(self.tcx, trait_ref),
&obligation.with(self.tcx, trait_pred),
);
let has_non_region_infer =
trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
let has_non_region_infer = trait_pred
.skip_binder()
.trait_ref
.args
.types()
.any(|t| !t.is_ty_or_numeric_infer());
// It doesn't make sense to talk about applicable impls if there are more than a
// handful of them. If there are a lot of them, but only a few of them have no type
// params, we only show those, as they are more likely to be useful/intended.
@ -294,7 +298,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if impl_candidates.len() < 40 {
self.report_similar_impl_candidates(
impl_candidates.as_slice(),
trait_ref,
trait_pred,
obligation.cause.body_id,
&mut err,
false,
@ -306,7 +310,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let ObligationCauseCode::WhereClause(def_id, _)
| ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
{
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_pred.def_id());
}
if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())

View file

@ -23,9 +23,7 @@ use rustc_middle::ty::print::{
FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _,
PrintTraitRefExt as _, with_forced_trimmed_paths,
};
use rustc_middle::ty::{
self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast,
};
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
use rustc_middle::{bug, span_bug};
use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};
use tracing::{debug, instrument};
@ -155,12 +153,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
(leaf_trait_predicate, &obligation)
};
let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();
if let Some(guar) = self.emit_specialized_closure_kind_error(
&obligation,
leaf_trait_ref,
leaf_trait_predicate,
) {
return guar;
}
@ -202,14 +197,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
} = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file);
let have_alt_message = message.is_some() || label.is_some();
let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id());
let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id());
let is_unsize =
self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Unsize);
self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize);
let (message, notes, append_const_msg) = if is_try_conversion {
(
Some(format!(
"`?` couldn't convert the error to `{}`",
main_trait_ref.skip_binder().self_ty(),
main_trait_predicate.skip_binder().self_ty(),
)),
vec![
"the question mark operation (`?`) implicitly performs a \
@ -230,12 +225,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
post_message,
);
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_ref.def_id(), LangItem::TransmuteTrait)
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
{
// Recompute the safe transmute reason and use that for the error reporting
match self.get_safe_transmute_error_and_reason(
obligation.clone(),
main_trait_ref,
main_trait_predicate,
span,
) {
GetSafeTransmuteErrorAndReason::Silent => {
@ -266,7 +261,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
let mut suggested = false;
if is_try_conversion {
suggested = self.try_conversion_context(&obligation, main_trait_ref.skip_binder(), &mut err);
suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
}
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
@ -274,12 +269,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
ret_span,
format!(
"expected `{}` because of this",
main_trait_ref.skip_binder().self_ty()
main_trait_predicate.skip_binder().self_ty()
),
);
}
if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Tuple) {
if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) {
self.add_tuple_trait_message(
obligation.cause.code().peel_derives(),
&mut err,
@ -319,7 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
err.span_label(span, s);
if !matches!(leaf_trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) {
// When the self type is a type param We don't need to "the trait
// `std::marker::Sized` is not implemented for `T`" as we will point
// at the type param with a label to suggest constraining it.
@ -339,7 +334,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let ObligationCauseCode::Coercion { source, target } =
*obligation.cause.code().peel_derives()
{
if self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Sized) {
if self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Sized) {
self.suggest_borrowing_for_object_cast(
&mut err,
root_obligation,
@ -368,7 +363,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err.span_label(tcx.def_span(body), s);
}
self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_ref);
self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_predicate);
self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate);
suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);
suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);
@ -376,7 +371,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
suggested = if let &[cand] = &impl_candidates[..] {
let cand = cand.trait_ref;
if let (ty::FnPtr(..), ty::FnDef(..)) =
(cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind())
(cand.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind())
{
// Wrap method receivers and `&`-references in parens
let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() {
@ -423,11 +418,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
span,
leaf_trait_predicate,
);
self.note_version_mismatch(&mut err, leaf_trait_ref);
self.note_version_mismatch(&mut err, leaf_trait_predicate);
self.suggest_remove_await(&obligation, &mut err);
self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);
if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Try) {
if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Try) {
self.suggest_await_before_try(
&mut err,
&obligation,
@ -455,9 +450,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
);
}
let is_fn_trait = tcx.is_fn_trait(leaf_trait_ref.def_id());
let is_fn_trait = tcx.is_fn_trait(leaf_trait_predicate.def_id());
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
*leaf_trait_ref.skip_binder().self_ty().kind()
*leaf_trait_predicate.skip_binder().self_ty().kind()
{
!self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
} else {
@ -509,7 +504,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause);
self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_ref);
self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_predicate);
// Return early if the trait is Debug or Display and the invocation
// originates within a standard library macro, because the output
@ -527,7 +522,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if in_std_macro
&& matches!(
self.tcx.get_diagnostic_name(leaf_trait_ref.def_id()),
self.tcx.get_diagnostic_name(leaf_trait_predicate.def_id()),
Some(sym::Debug | sym::Display)
)
{
@ -785,21 +780,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn emit_specialized_closure_kind_error(
&self,
obligation: &PredicateObligation<'tcx>,
mut trait_ref: ty::PolyTraitRef<'tcx>,
mut trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<ErrorGuaranteed> {
// If `AsyncFnKindHelper` is not implemented, that means that the closure kind
// doesn't extend the goal kind. This is worth reporting, but we can only do so
// if we actually know which closure this goal comes from, so look at the cause
// to see if we can extract that information.
if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::AsyncFnKindHelper)
&& let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind()
if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper)
&& let Some(found_kind) =
trait_pred.skip_binder().trait_ref.args.type_at(0).to_opt_closure_kind()
&& let Some(expected_kind) =
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
trait_pred.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind()
&& !found_kind.extends(expected_kind)
{
if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
trait_ref = parent.to_poly_trait_ref();
trait_pred = parent;
} else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
obligation.cause.code()
&& let Some(typeck_results) = &self.typeck_results
@ -820,9 +816,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}
let self_ty = trait_ref.self_ty().skip_binder();
let self_ty = trait_pred.self_ty().skip_binder();
if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) {
if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {
let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
ty::Closure(def_id, args) => {
(def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
@ -837,7 +833,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
_ => return None,
};
let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1));
let expected_args =
trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));
// Verify that the arguments are compatible. If the signature is
// mismatched, then we have a totally different error to report.
@ -909,7 +906,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn try_conversion_context(
&self,
obligation: &PredicateObligation<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
err: &mut Diag<'_>,
) -> bool {
let span = obligation.cause.span;
@ -953,8 +950,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
return false;
}
let self_ty = trait_ref.self_ty();
let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type());
let self_ty = trait_pred.skip_binder().self_ty();
let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
let mut prev_ty = self.resolve_vars_if_possible(
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
@ -1223,18 +1220,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
goal: ty::TraitPredicate<'tcx>,
assumption: ty::PolyTraitPredicate<'tcx>,
) -> bool {
// Fast path
if goal.polarity != assumption.polarity() {
return false;
}
let trait_goal = goal.trait_ref;
let trait_assumption = self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
infer::BoundRegionConversionTime::HigherRankedType,
assumption.to_poly_trait_ref(),
assumption,
);
self.can_eq(ty::ParamEnv::empty(), trait_goal, trait_assumption)
self.can_eq(ty::ParamEnv::empty(), goal.trait_ref, trait_assumption.trait_ref)
}
fn can_match_projection(
@ -1682,7 +1679,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub(super) fn report_similar_impl_candidates(
&self,
impl_candidates: &[ImplCandidate<'tcx>],
trait_ref: ty::PolyTraitRef<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
body_def_id: LocalDefId,
err: &mut Diag<'_>,
other: bool,
@ -1727,7 +1724,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// We'll check for the case where the reason for the mismatch is that the trait comes from
// one crate version and the type comes from another crate version, even though they both
// are from the same crate.
let trait_def_id = trait_ref.def_id();
let trait_def_id = trait_pred.def_id();
let trait_name = self.tcx.item_name(trait_def_id);
let crate_name = self.tcx.crate_name(trait_def_id.krate);
if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| {
@ -1739,7 +1736,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// different crate `DefId`. We highlight the traits.
let found_type =
if let ty::Adt(def, _) = trait_ref.self_ty().skip_binder().peel_refs().kind() {
if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() {
Some(def.did())
} else {
None
@ -1836,7 +1833,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if self.probe(|_| {
let ocx = ObligationCtxt::new(self);
self.enter_forall(trait_ref, |obligation_trait_ref| {
self.enter_forall(trait_pred, |obligation_trait_ref| {
let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
let impl_trait_ref = ocx.normalize(
&ObligationCause::dummy(),
@ -1864,7 +1861,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut terrs = vec![];
for (obligation_arg, impl_arg) in
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
std::iter::zip(obligation_trait_ref.trait_ref.args, impl_trait_ref.args)
{
if (obligation_arg, impl_arg).references_error() {
return false;
@ -1906,8 +1903,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
let traits = self.cmp_traits(
obligation_trait_ref.def_id,
&obligation_trait_ref.args[1..],
obligation_trait_ref.def_id(),
&obligation_trait_ref.trait_ref.args[1..],
impl_trait_ref.def_id,
&impl_trait_ref.args[1..],
);
@ -1991,7 +1988,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
if let &[cand] = &candidates[..] {
let (desc, mention_castable) =
match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
match (cand.self_ty().kind(), trait_pred.self_ty().skip_binder().kind()) {
(ty::FnPtr(..), ty::FnDef(..)) => {
(" implemented for fn pointer `", ", cast using `as`")
}
@ -2055,7 +2052,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
.filter(|cand| !self.tcx.do_not_recommend_impl(cand.impl_def_id))
.collect::<Vec<_>>();
let def_id = trait_ref.def_id();
let def_id = trait_pred.def_id();
if impl_candidates.is_empty() {
if self.tcx.trait_is_auto(def_id)
|| self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
@ -2132,11 +2129,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&& !self.tcx.trait_is_auto(def_id)
&& !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
{
let trait_ref = trait_pred.to_poly_trait_ref();
let impl_candidates = self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
&impl_candidates,
trait_ref,
trait_pred,
body_def_id,
err,
true,
@ -2173,12 +2169,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
/// with the same path as `trait_ref`, a help message about
/// a probable version mismatch is added to `err`
fn note_version_mismatch(&self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>) -> bool {
fn note_version_mismatch(
&self,
err: &mut Diag<'_>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
let get_trait_impls = |trait_def_id| {
let mut trait_impls = vec![];
self.tcx.for_each_relevant_impl(
trait_def_id,
trait_ref.skip_binder().self_ty(),
trait_pred.skip_binder().self_ty(),
|impl_def_id| {
trait_impls.push(impl_def_id);
},
@ -2186,11 +2186,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_impls
};
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
let required_trait_path = self.tcx.def_path_str(trait_pred.def_id());
let traits_with_same_path: UnordSet<_> = self
.tcx
.visible_traits()
.filter(|trait_def_id| *trait_def_id != trait_ref.def_id())
.filter(|trait_def_id| *trait_def_id != trait_pred.def_id())
.map(|trait_def_id| (self.tcx.def_path_str(trait_def_id), trait_def_id))
.filter(|(p, _)| *p == required_trait_path)
.collect();
@ -2374,7 +2374,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn get_safe_transmute_error_and_reason(
&self,
obligation: PredicateObligation<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
span: Span,
) -> GetSafeTransmuteErrorAndReason {
use rustc_transmute::Answer;
@ -2386,19 +2386,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
// Erase regions because layout code doesn't particularly care about regions.
let trait_ref =
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
let trait_pred =
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_pred));
let src_and_dst = rustc_transmute::Types {
dst: trait_ref.args.type_at(0),
src: trait_ref.args.type_at(1),
dst: trait_pred.trait_ref.args.type_at(0),
src: trait_pred.trait_ref.args.type_at(1),
};
let ocx = ObligationCtxt::new(self);
let Ok(assume) = ocx.structurally_normalize_const(
&obligation.cause,
obligation.param_env,
trait_ref.args.const_at(2),
trait_pred.trait_ref.args.const_at(2),
) else {
self.dcx().span_delayed_bug(
span,
@ -2417,8 +2417,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return GetSafeTransmuteErrorAndReason::Silent;
};
let dst = trait_ref.args.type_at(0);
let src = trait_ref.args.type_at(1);
let dst = trait_pred.trait_ref.args.type_at(0);
let src = trait_pred.trait_ref.args.type_at(1);
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@ -2566,12 +2566,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_predicate.skip_binder().polarity,
)
{
self.add_help_message_for_fn_trait(
trait_predicate.to_poly_trait_ref(),
err,
implemented_kind,
params,
);
self.add_help_message_for_fn_trait(trait_predicate, err, implemented_kind, params);
} else if !trait_predicate.has_non_region_infer()
&& self.predicate_can_apply(obligation.param_env, trait_predicate)
{
@ -2606,7 +2601,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
if !self.report_similar_impl_candidates(
&impl_candidates,
trait_predicate.to_poly_trait_ref(),
trait_predicate,
body_def_id,
err,
true,
@ -2623,7 +2618,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
self.suggest_convert_to_slice(
err,
obligation,
trait_predicate.to_poly_trait_ref(),
trait_predicate,
impl_candidates.as_slice(),
span,
);
@ -2634,7 +2629,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn add_help_message_for_fn_trait(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
err: &mut Diag<'_>,
implemented_kind: ty::ClosureKind,
params: ty::Binder<'tcx, Ty<'tcx>>,
@ -2647,12 +2642,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// to implement.
let selected_kind = self
.tcx
.fn_trait_kind_from_def_id(trait_ref.def_id())
.fn_trait_kind_from_def_id(trait_pred.def_id())
.expect("expected to map DefId to ClosureKind");
if !implemented_kind.extends(selected_kind) {
err.note(format!(
"`{}` implements `{}`, but it must implement `{}`, which is more general",
trait_ref.skip_binder().self_ty(),
trait_pred.skip_binder().self_ty(),
implemented_kind,
selected_kind
));
@ -2660,7 +2655,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Note any argument mismatches
let given_ty = params.skip_binder();
let expected_ty = trait_ref.skip_binder().args.type_at(1);
let expected_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
if let ty::Tuple(given) = given_ty.kind()
&& let ty::Tuple(expected) = expected_ty.kind()
{

View file

@ -10,7 +10,7 @@ use rustc_hir::{AttrArgs, AttrKind, Attribute};
use rustc_macros::LintDiagnostic;
use rustc_middle::bug;
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, TyCtxt};
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt};
use rustc_parse_format::{ParseMode, Parser, Piece, Position};
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::{Span, Symbol, kw, sym};
@ -42,18 +42,18 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn impl_similar_to(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
obligation: &PredicateObligation<'tcx>,
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
let tcx = self.tcx;
let param_env = obligation.param_env;
self.enter_forall(trait_ref, |trait_ref| {
let trait_self_ty = trait_ref.self_ty();
self.enter_forall(trait_pred, |trait_pred| {
let trait_self_ty = trait_pred.self_ty();
let mut self_match_impls = vec![];
let mut fuzzy_match_impls = vec![];
self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
self.tcx.for_each_relevant_impl(trait_pred.def_id(), trait_self_ty, |def_id| {
let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id);
let impl_trait_ref =
tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args);
@ -64,7 +64,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
self_match_impls.push((def_id, impl_args));
if iter::zip(
trait_ref.args.types().skip(1),
trait_pred.trait_ref.args.types().skip(1),
impl_trait_ref.args.types().skip(1),
)
.all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
@ -117,7 +117,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
let (def_id, args) = self
.impl_similar_to(trait_pred.to_poly_trait_ref(), obligation)
.impl_similar_to(trait_pred, obligation)
.unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
let trait_pred = trait_pred.skip_binder();

View file

@ -32,9 +32,9 @@ use rustc_middle::ty::print::{
with_forced_trimmed_paths, with_no_trimmed_paths,
};
use rustc_middle::ty::{
self, AdtKind, GenericArgs, InferTy, IsSuggestable, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable,
TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast,
suggest_arbitrary_trait_bound, suggest_constraining_type_param,
self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast, suggest_arbitrary_trait_bound,
suggest_constraining_type_param,
};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::LocalDefId;
@ -218,15 +218,15 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
(_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
(None, Some((ident, []))) => (
ident.span.shrink_to_hi(),
format!(": {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
format!(": {}", trait_pred.print_modifiers_and_trait_path()),
),
(_, Some((_, [.., bounds]))) => (
bounds.span().shrink_to_hi(),
format!(" + {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
),
(Some(_), Some((_, []))) => (
hir_generics.span.shrink_to_hi(),
format!(": {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
format!(": {}", trait_pred.print_modifiers_and_trait_path()),
),
};
@ -3729,7 +3729,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut Diag<'_>,
trait_ref: ty::PolyTraitRef<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
let rhs_span = match obligation.cause.code() {
ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => {
@ -3737,8 +3737,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
_ => return,
};
if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind()
&& let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().args.type_at(1).kind()
if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind()
&& let ty::Infer(InferTy::IntVar(_)) =
trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
{
err.span_suggestion_verbose(
rhs_span.shrink_to_hi(),
@ -4448,7 +4449,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
err: &mut Diag<'_>,
obligation: &PredicateObligation<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
candidate_impls: &[ImplCandidate<'tcx>],
span: Span,
) {
@ -4464,7 +4465,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// 1. `[T; _]` (array of T)
// 2. `&[T; _]` (reference to array of T)
// 3. `&mut [T; _]` (mutable reference to array of T)
let (element_ty, mut mutability) = match *trait_ref.skip_binder().self_ty().kind() {
let (element_ty, mut mutability) = match *trait_pred.skip_binder().self_ty().kind() {
ty::Array(element_ty, _) => (element_ty, None),
ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() {
@ -4620,14 +4621,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub(super) fn suggest_desugaring_async_fn_in_trait(
&self,
err: &mut Diag<'_>,
trait_ref: ty::PolyTraitRef<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
// Don't suggest if RTN is active -- we should prefer a where-clause bound instead.
if self.tcx.features().return_type_notation() {
return;
}
let trait_def_id = trait_ref.def_id();
let trait_def_id = trait_pred.def_id();
// Only suggest specifying auto traits
if !self.tcx.trait_is_auto(trait_def_id) {
@ -4635,7 +4636,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
// Look for an RPITIT
let ty::Alias(ty::Projection, alias_ty) = trait_ref.self_ty().skip_binder().kind() else {
let ty::Alias(ty::Projection, alias_ty) = trait_pred.self_ty().skip_binder().kind() else {
return;
};
let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =

View file

@ -16,7 +16,7 @@ use rustc_infer::traits::{
Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
};
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode};
use rustc_middle::{bug, span_bug};
use rustc_type_ir::Interner;
use tracing::{debug, instrument, trace};
@ -186,10 +186,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
selcx.infcx.probe(|_| {
// We checked the polarity already
match selcx.match_normalize_trait_ref(
obligation,
placeholder_trait_predicate.trait_ref,
bound.to_poly_trait_ref(),
bound.map_bound(|pred| pred.trait_ref),
) {
Ok(None) => {
candidates.vec.push(ProjectionCandidate(idx));

View file

@ -16,7 +16,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
use rustc_middle::ty::{self, GenericArgsRef, ToPolyTraitRef, Ty, TyCtxt, Upcast};
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
use rustc_type_ir::elaborate;
@ -458,8 +458,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ensure_sufficient_stack(|| {
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref);
assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive);
let trait_ref =
self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref;
let trait_obligations = self.impl_or_trait_obligations(
&cause,
obligation.recursion_depth + 1,

View file

@ -97,6 +97,11 @@ tidy:
prepare:
$(Q)$(BOOTSTRAP) build --stage 2 --dry-run
# Set of tests that represent around half of the time of the test suite.
# Used to split tests across multiple CI runners.
STAGE_2_TEST_SET1 := test --stage 2 --skip=compiler --skip=src
STAGE_2_TEST_SET2 := test --stage 2 --skip=tests --skip=coverage-map --skip=coverage-run --skip=library --skip=tidyselftest
## MSVC native builders
# this intentionally doesn't use `$(BOOTSTRAP)` so we can test the shebang on Windows
@ -105,6 +110,10 @@ ci-msvc-py:
ci-msvc-ps1:
$(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 --skip tidy
ci-msvc: ci-msvc-py ci-msvc-ps1
ci-msvc-py-set1:
$(Q)$(CFG_SRC_DIR)/x.py $(STAGE_2_TEST_SET1)
ci-msvc-ps1-set2:
$(Q)$(CFG_SRC_DIR)/x.ps1 $(STAGE_2_TEST_SET2)
## MingW native builders
@ -112,9 +121,9 @@ ci-msvc: ci-msvc-py ci-msvc-ps1
# Used to split tests across multiple CI runners.
# Test both x and bootstrap entrypoints.
ci-mingw-x:
$(Q)$(CFG_SRC_DIR)/x test --stage 2 --skip=compiler --skip=src
$(Q)$(CFG_SRC_DIR)/x $(STAGE_2_TEST_SET1)
ci-mingw-bootstrap:
$(Q)$(BOOTSTRAP) test --stage 2 --skip=tests --skip=coverage-map --skip=coverage-run --skip=library --skip=tidyselftest
$(Q)$(BOOTSTRAP) $(STAGE_2_TEST_SET2)
ci-mingw: ci-mingw-x ci-mingw-bootstrap
.PHONY: dist

View file

@ -305,8 +305,6 @@ For targets: `mips-unknown-linux-gnu`
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
- Path and misc options > Use a mirror = ENABLE
- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
- Path and misc options > Patches origin = Bundled, then local
- Path and misc options > Local patch directory = /tmp/patches
- Target options > Target Architecture = mips
- Target options > ABI = o32
- Target options > Endianness = Big endian
@ -327,8 +325,6 @@ For targets: `mipsel-unknown-linux-gnu`
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
- Path and misc options > Use a mirror = ENABLE
- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
- Path and misc options > Patches origin = Bundled, then local
- Path and misc options > Local patch directory = /tmp/patches
- Target options > Target Architecture = mips
- Target options > ABI = o32
- Target options > Endianness = Little endian
@ -349,8 +345,6 @@ For targets: `mips64-unknown-linux-gnuabi64`
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
- Path and misc options > Use a mirror = ENABLE
- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
- Path and misc options > Patches origin = Bundled, then local
- Path and misc options > Local patch directory = /tmp/patches
- Target options > Target Architecture = mips
- Target options > ABI = n64
- Target options > Endianness = Big endian
@ -370,8 +364,6 @@ For targets: `mips64el-unknown-linux-gnuabi64`
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
- Path and misc options > Use a mirror = ENABLE
- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
- Path and misc options > Patches origin = Bundled, then local
- Path and misc options > Local patch directory = /tmp/patches
- Target options > Target Architecture = mips
- Target options > ABI = n64
- Target options > Endianness = Little endian

View file

@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
WORKDIR /tmp
COPY scripts/crosstool-ng-build.sh /scripts/
COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
COPY host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig /tmp/crosstool.defconfig
RUN /scripts/crosstool-ng-build.sh

View file

@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
CT_USE_MIRROR=y
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
CT_PATCH_BUNDLED_LOCAL=y
CT_LOCAL_PATCH_DIR="/tmp/patches"
CT_ARCH_MIPS=y
CT_ARCH_mips_o32=y
CT_ARCH_ARCH="mips32r2"

View file

@ -1,44 +0,0 @@
From 43c2948756bb6e144c7b871e827bba37d61ad3a3 Mon Sep 17 00:00:00 2001
From: Aurelien Jarno <aurelien@aurel32.net>
Date: Sat, 18 Jun 2016 19:11:23 +0200
Subject: [PATCH 1/2] MIPS, SPARC: fix wrong vfork aliases in libpthread.so
With recent binutils versions the GNU libc fails to build on at least
MISP and SPARC, with this kind of error:
/home/aurel32/glibc/glibc-build/nptl/libpthread.so:(*IND*+0x0): multiple definition of `vfork@GLIBC_2.0'
/home/aurel32/glibc/glibc-build/nptl/libpthread.so::(.text+0xee50): first defined here
It appears that on these architectures pt-vfork.S includes vfork.S
(through the alpha version of pt-vfork.S) and that the __vfork aliases
are not conditionalized on IS_IN (libc) like on other architectures.
Therefore the aliases are also wrongly included in libpthread.so.
Fix this by properly conditionalizing the aliases like on other
architectures.
Changelog:
* sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Conditionalize
hidden_def, weak_alias and strong_alias on [IS_IN (libc)].
* sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
---
sysdeps/unix/sysv/linux/mips/vfork.S | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
index 8c6615143708..c0c0ce699159 100644
--- a/sysdeps/unix/sysv/linux/mips/vfork.S
+++ b/sysdeps/unix/sysv/linux/mips/vfork.S
@@ -106,6 +106,8 @@ L(error):
#endif
END(__vfork)
+#if IS_IN (libc)
libc_hidden_def(__vfork)
weak_alias (__vfork, vfork)
strong_alias (__vfork, __libc_vfork)
+#endif
--
2.37.3

View file

@ -1,63 +0,0 @@
From b87c1ec3fa398646f042a68f0ce0f7d09c1348c7 Mon Sep 17 00:00:00 2001
From: Aurelien Jarno <aurelien@aurel32.net>
Date: Tue, 21 Jun 2016 23:59:37 +0200
Subject: [PATCH 2/2] MIPS, SPARC: more fixes to the vfork aliases in
libpthread.so
Commit 43c29487 tried to fix the vfork aliases in libpthread.so on MIPS
and SPARC, but failed to do it correctly, introducing an ABI change.
This patch does the remaining changes needed to align the MIPS and SPARC
vfork implementations with the other architectures. That way the the
alpha version of pt-vfork.S works correctly for MIPS and SPARC. The
changes for alpha were done in 82aab97c.
Changelog:
* sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Rename into
__libc_vfork.
(__vfork) [IS_IN (libc)]: Remove alias.
(__libc_vfork) [IS_IN (libc)]: Define as an alias.
* sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
---
sysdeps/unix/sysv/linux/mips/vfork.S | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
index c0c0ce699159..1867c8626ebe 100644
--- a/sysdeps/unix/sysv/linux/mips/vfork.S
+++ b/sysdeps/unix/sysv/linux/mips/vfork.S
@@ -31,13 +31,13 @@
LOCALSZ= 1
FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
GPOFF= FRAMESZ-(1*SZREG)
-NESTED(__vfork,FRAMESZ,sp)
+NESTED(__libc_vfork,FRAMESZ,sp)
#ifdef __PIC__
SETUP_GP
#endif
PTR_SUBU sp, FRAMESZ
cfi_adjust_cfa_offset (FRAMESZ)
- SETUP_GP64_REG (a5, __vfork)
+ SETUP_GP64_REG (a5, __libc_vfork)
#ifdef __PIC__
SAVE_GP (GPOFF)
#endif
@@ -104,10 +104,10 @@ L(error):
RESTORE_GP64_REG
j __syscall_error
#endif
- END(__vfork)
+ END(__libc_vfork)
#if IS_IN (libc)
-libc_hidden_def(__vfork)
-weak_alias (__vfork, vfork)
-strong_alias (__vfork, __libc_vfork)
+weak_alias (__libc_vfork, vfork)
+strong_alias (__libc_vfork, __vfork)
+libc_hidden_def (__vfork)
#endif
--
2.37.3

View file

@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
WORKDIR /tmp
COPY scripts/crosstool-ng-build.sh /scripts/
COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
COPY host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig /tmp/crosstool.defconfig
RUN /scripts/crosstool-ng-build.sh

View file

@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
CT_USE_MIRROR=y
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
CT_PATCH_BUNDLED_LOCAL=y
CT_LOCAL_PATCH_DIR="/tmp/patches"
CT_ARCH_MIPS=y
CT_ARCH_mips_n64=y
CT_ARCH_64=y

View file

@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
WORKDIR /tmp
COPY scripts/crosstool-ng-build.sh /scripts/
COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
COPY host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig /tmp/crosstool.defconfig
RUN /scripts/crosstool-ng-build.sh

View file

@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
CT_USE_MIRROR=y
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
CT_PATCH_BUNDLED_LOCAL=y
CT_LOCAL_PATCH_DIR="/tmp/patches"
CT_ARCH_MIPS=y
CT_ARCH_mips_n64=y
CT_ARCH_LE=y

View file

@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
WORKDIR /tmp
COPY scripts/crosstool-ng-build.sh /scripts/
COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
COPY host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig /tmp/crosstool.defconfig
RUN /scripts/crosstool-ng-build.sh

View file

@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
CT_USE_MIRROR=y
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
CT_PATCH_BUNDLED_LOCAL=y
CT_LOCAL_PATCH_DIR="/tmp/patches"
CT_ARCH_MIPS=y
CT_ARCH_mips_o32=y
CT_ARCH_LE=y

View file

@ -1,4 +1,6 @@
FROM ubuntu:22.04
# We use the ghcr base image because ghcr doesn't have a rate limit
# and the mingw-check-tidy job doesn't cache docker images in CI.
FROM ghcr.io/rust-lang/ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \

View file

@ -448,11 +448,18 @@ auto:
SCRIPT: make ci-msvc
<<: *job-windows-8c
- name: i686-msvc
# i686-msvc is split into two jobs to run tests in parallel.
- name: i686-msvc-1
env:
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
SCRIPT: make ci-msvc
<<: *job-windows-8c
SCRIPT: make ci-msvc-py-set1
<<: *job-windows
- name: i686-msvc-2
env:
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
SCRIPT: make ci-msvc-ps1-set2
<<: *job-windows
# x86_64-msvc-ext is split into multiple jobs to run tests in parallel.
- name: x86_64-msvc-ext1

View file

@ -0,0 +1,19 @@
error[E0005]: refutable pattern in local binding
--> $DIR/resolve-issue-135614-assoc-const.rs:21:9
|
LL | let DEFAULT: u32 = 0;
| ^^^^^^^ pattern `1_u32..=u32::MAX` not covered
LL | const DEFAULT: u32 = 0;
| ------------------ missing patterns are not covered because `DEFAULT` is interpreted as a constant pattern, not a new variable
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
= note: the matched value is of type `u32`
help: introduce a variable instead
|
LL | let DEFAULT_var: u32 = 0;
| ~~~~~~~~~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0005`.

View file

@ -0,0 +1,30 @@
error[E0658]: `use` associated items of traits is unstable
--> $DIR/resolve-issue-135614-assoc-const.rs:6:5
|
LL | use MyDefault::DEFAULT;
| ^^^^^^^^^^^^^^^^^^
|
= note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0005]: refutable pattern in local binding
--> $DIR/resolve-issue-135614-assoc-const.rs:21:9
|
LL | let DEFAULT: u32 = 0;
| ^^^^^^^ pattern `1_u32..=u32::MAX` not covered
LL | const DEFAULT: u32 = 0;
| ------------------ missing patterns are not covered because `DEFAULT` is interpreted as a constant pattern, not a new variable
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
= note: the matched value is of type `u32`
help: introduce a variable instead
|
LL | let DEFAULT_var: u32 = 0;
| ~~~~~~~~~~~
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0005, E0658.
For more information about an error, try `rustc --explain E0005`.

View file

@ -0,0 +1,30 @@
//@ revisions: normal import_trait_associated_functions
#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))]
// Makes sure that imported constant can be used in pattern bindings.
use MyDefault::DEFAULT; //[normal]~ ERROR `use` associated items of traits is unstable
trait MyDefault {
const DEFAULT: Self;
}
impl MyDefault for u32 {
const DEFAULT: u32 = 0;
}
impl MyDefault for () {
const DEFAULT: () = ();
}
fn foo(x: u32) -> u32 {
let DEFAULT: u32 = 0; //~ ERROR refutable pattern in local binding
const DEFAULT: u32 = 0;
if let DEFAULT = x { DEFAULT } else { 1 }
}
fn bar() {
let DEFAULT = ();
}
fn main() {}

View file

@ -0,0 +1,13 @@
error[E0658]: `use` associated items of traits is unstable
--> $DIR/resolve-issue-135614.rs:7:5
|
LL | use A::b;
| ^^^^
|
= note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,15 @@
//@ revisions: normal import_trait_associated_functions
//@[import_trait_associated_functions] check-pass
#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))]
// Makes sure that imported associated functions are shadowed by the local declarations.
use A::b; //[normal]~ ERROR `use` associated items of traits is unstable
trait A {
fn b() {}
}
fn main() {
let b: ();
}