summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/traits
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/traits')
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs135
-rw-r--r--compiler/rustc_middle/src/traits/query.rs11
-rw-r--r--compiler/rustc_middle/src/traits/select.rs36
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs21
-rw-r--r--compiler/rustc_middle/src/traits/solve/cache.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect.rs11
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs13
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs2
8 files changed, 148 insertions, 83 deletions
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 6cd75e087..5d0187a85 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -250,9 +250,6 @@ pub enum ObligationCauseCode<'tcx> {
/// A tuple is WF only if its middle elements are `Sized`.
TupleElem,
- /// This is the trait reference from the given projection.
- ProjectionWf(ty::AliasTy<'tcx>),
-
/// Must satisfy all of the where-clause predicates of the
/// given item.
ItemObligation(DefId),
@@ -343,7 +340,8 @@ pub enum ObligationCauseCode<'tcx> {
parent_code: InternedObligationCauseCode<'tcx>,
},
- /// Error derived when matching traits/impls; see ObligationCause for more details
+ /// Error derived when checking an impl item is compatible with
+ /// its corresponding trait item's definition
CompareImplItemObligation {
impl_item_def_id: LocalDefId,
trait_item_def_id: DefId,
@@ -372,9 +370,6 @@ pub enum ObligationCauseCode<'tcx> {
origin_expr: bool,
},
- /// Constants in patterns must have `Structural` type.
- ConstPatternStructural,
-
/// Computing common supertype in an if expression
IfExpression(Box<IfExpressionCause<'tcx>>),
@@ -407,9 +402,6 @@ pub enum ObligationCauseCode<'tcx> {
/// `return` with an expression
ReturnValue(hir::HirId),
- /// Return type of this function
- ReturnType,
-
/// Opaque return type of this function
OpaqueReturnType(Option<(Ty<'tcx>, Span)>),
@@ -419,10 +411,7 @@ pub enum ObligationCauseCode<'tcx> {
/// #[feature(trivial_bounds)] is not enabled
TrivialBound,
- /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y`
- OpaqueType,
-
- AwaitableExpr(Option<hir::HirId>),
+ AwaitableExpr(hir::HirId),
ForLoopIterator,
@@ -686,7 +675,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
pub fn borrow_nested_obligations(&self) -> &[N] {
match self {
ImplSource::UserDefined(i) => &i.nested,
- ImplSource::Param(n) | ImplSource::Builtin(_, n) => &n,
+ ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
}
}
@@ -843,50 +832,31 @@ impl ObjectSafetyViolation {
}
}
- pub fn solution(&self, err: &mut Diagnostic) {
+ pub fn solution(&self) -> ObjectSafetyViolationSolution {
match self {
ObjectSafetyViolation::SizedSelf(_)
| ObjectSafetyViolation::SupertraitSelf(_)
- | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => {}
+ | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => {
+ ObjectSafetyViolationSolution::None
+ }
ObjectSafetyViolation::Method(
name,
MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))),
_,
- ) => {
- err.span_suggestion(
- add_self_sugg.1,
- format!(
- "consider turning `{name}` into a method by giving it a `&self` argument"
- ),
- add_self_sugg.0.to_string(),
- Applicability::MaybeIncorrect,
- );
- err.span_suggestion(
- make_sized_sugg.1,
- format!(
- "alternatively, consider constraining `{name}` so it does not apply to \
- trait objects"
- ),
- make_sized_sugg.0.to_string(),
- Applicability::MaybeIncorrect,
- );
- }
+ ) => ObjectSafetyViolationSolution::AddSelfOrMakeSized {
+ name: *name,
+ add_self_sugg: add_self_sugg.clone(),
+ make_sized_sugg: make_sized_sugg.clone(),
+ },
ObjectSafetyViolation::Method(
name,
MethodViolationCode::UndispatchableReceiver(Some(span)),
_,
- ) => {
- err.span_suggestion(
- *span,
- format!("consider changing method `{name}`'s `self` parameter to be `&self`"),
- "&Self",
- Applicability::MachineApplicable,
- );
- }
+ ) => ObjectSafetyViolationSolution::ChangeToRefSelf(*name, *span),
ObjectSafetyViolation::AssocConst(name, _)
| ObjectSafetyViolation::GAT(name, _)
| ObjectSafetyViolation::Method(name, ..) => {
- err.help(format!("consider moving `{name}` to another trait"));
+ ObjectSafetyViolationSolution::MoveToAnotherTrait(*name)
}
}
}
@@ -910,6 +880,60 @@ impl ObjectSafetyViolation {
}
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum ObjectSafetyViolationSolution {
+ None,
+ AddSelfOrMakeSized {
+ name: Symbol,
+ add_self_sugg: (String, Span),
+ make_sized_sugg: (String, Span),
+ },
+ ChangeToRefSelf(Symbol, Span),
+ MoveToAnotherTrait(Symbol),
+}
+
+impl ObjectSafetyViolationSolution {
+ pub fn add_to(self, err: &mut Diagnostic) {
+ match self {
+ ObjectSafetyViolationSolution::None => {}
+ ObjectSafetyViolationSolution::AddSelfOrMakeSized {
+ name,
+ add_self_sugg,
+ make_sized_sugg,
+ } => {
+ err.span_suggestion(
+ add_self_sugg.1,
+ format!(
+ "consider turning `{name}` into a method by giving it a `&self` argument"
+ ),
+ add_self_sugg.0,
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion(
+ make_sized_sugg.1,
+ format!(
+ "alternatively, consider constraining `{name}` so it does not apply to \
+ trait objects"
+ ),
+ make_sized_sugg.0,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ ObjectSafetyViolationSolution::ChangeToRefSelf(name, span) => {
+ err.span_suggestion(
+ span,
+ format!("consider changing method `{name}`'s `self` parameter to be `&self`"),
+ "&Self",
+ Applicability::MachineApplicable,
+ );
+ }
+ ObjectSafetyViolationSolution::MoveToAnotherTrait(name) => {
+ err.help(format!("consider moving `{name}` to another trait"));
+ }
+ }
+ }
+}
+
/// Reasons a method might not be object-safe.
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
pub enum MethodViolationCode {
@@ -956,13 +980,26 @@ pub enum CodegenObligationError {
FulfillmentError,
}
+/// Defines the treatment of opaque types in a given inference context.
+///
+/// This affects both what opaques are allowed to be defined, but also whether
+/// opaques are replaced with inference vars eagerly in the old solver (e.g.
+/// in projection, and in the signature during function type-checking).
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum DefiningAnchor {
- /// `DefId` of the item.
+ /// Define opaques which are in-scope of the `LocalDefId`. Also, eagerly
+ /// replace opaque types in `replace_opaque_types_with_inference_vars`.
Bind(LocalDefId),
- /// When opaque types are not resolved, we `Bubble` up, meaning
- /// return the opaque/hidden type pair from query, for caller of query to handle it.
+ /// In contexts where we don't currently know what opaques are allowed to be
+ /// defined, such as (old solver) canonical queries, we will simply allow
+ /// opaques to be defined, but "bubble" them up in the canonical response or
+ /// otherwise treat them to be handled later.
+ ///
+ /// We do not eagerly replace opaque types in `replace_opaque_types_with_inference_vars`,
+ /// which may affect what predicates pass and fail in the old trait solver.
Bubble,
- /// Used to catch type mismatch errors when handling opaque types.
+ /// Do not allow any opaques to be defined. This is used to catch type mismatch
+ /// errors when handling opaque types, and also should be used when we would
+ /// otherwise reveal opaques (such as [`Reveal::All`] reveal mode).
Error,
}
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 3cceb8b2c..34c56eb0d 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -108,17 +108,6 @@ impl<'tcx> DropckOutlivesResult<'tcx> {
tcx.sess.emit_err(DropCheckOverflow { span, ty, overflow_ty: *overflow_ty });
}
}
-
- pub fn into_kinds_reporting_overflows(
- self,
- tcx: TyCtxt<'tcx>,
- span: Span,
- ty: Ty<'tcx>,
- ) -> Vec<GenericArg<'tcx>> {
- self.report_overflows(tcx, span, ty);
- let DropckOutlivesResult { kinds, overflows: _ } = self;
- kinds
- }
}
/// A set of constraints that need to be satisfied in order for
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index f33421bba..734c2b61c 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -125,10 +125,8 @@ pub enum SelectionCandidate<'tcx> {
/// This is a trait matching with a projected type as `Self`, and we found
/// an applicable bound in the trait definition. The `usize` is an index
- /// into the list returned by `tcx.item_bounds`. The constness is the
- /// constness of the bound in the trait.
- // FIXME(effects) do we need this constness
- ProjectionCandidate(usize, ty::BoundConstness),
+ /// into the list returned by `tcx.item_bounds`.
+ ProjectionCandidate(usize),
/// Implementation of a `Fn`-family trait by one of the anonymous types
/// generated for an `||` expression.
@@ -144,14 +142,18 @@ pub enum SelectionCandidate<'tcx> {
/// generated for an async construct.
FutureCandidate,
- /// Implementation of an `Iterator` trait by one of the generator types
- /// generated for a gen construct.
+ /// Implementation of an `Iterator` trait by one of the coroutine types
+ /// generated for a `gen` construct.
IteratorCandidate,
+ /// Implementation of an `AsyncIterator` trait by one of the coroutine types
+ /// generated for a `async gen` construct.
+ AsyncIteratorCandidate,
+
/// Implementation of a `Fn`-family trait by one of the anonymous
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
FnPointerCandidate {
- is_const: bool,
+ fn_host_effect: ty::Const<'tcx>,
},
TraitAliasCandidate,
@@ -180,8 +182,8 @@ pub enum SelectionCandidate<'tcx> {
///
/// The evaluation results are ordered:
/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
-/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
-/// - `EvaluatedToErr` implies `EvaluatedToRecur`
+/// implies `EvaluatedToAmbig` implies `EvaluatedToAmbigStackDependent`
+/// - `EvaluatedToErr` implies `EvaluatedToErrStackDependent`
/// - the "union" of evaluation results is equal to their maximum -
/// all the "potential success" candidates can potentially succeed,
/// so they are noops when unioned with a definite error, and within
@@ -199,7 +201,7 @@ pub enum EvaluationResult {
/// Evaluation is known to be ambiguous -- it *might* hold for some
/// assignment of inference variables, but it might not.
///
- /// While this has the same meaning as `EvaluatedToUnknown` -- we can't
+ /// While this has the same meaning as `EvaluatedToAmbigStackDependent` -- we can't
/// know whether this obligation holds or not -- it is the result we
/// would get with an empty stack, and therefore is cacheable.
EvaluatedToAmbig,
@@ -207,8 +209,8 @@ pub enum EvaluationResult {
/// variables. We are somewhat imprecise there, so we don't actually
/// know the real result.
///
- /// This can't be trivially cached for the same reason as `EvaluatedToRecur`.
- EvaluatedToUnknown,
+ /// This can't be trivially cached for the same reason as `EvaluatedToErrStackDependent`.
+ EvaluatedToAmbigStackDependent,
/// Evaluation failed because we encountered an obligation we are already
/// trying to prove on this branch.
///
@@ -247,12 +249,12 @@ pub enum EvaluationResult {
/// does not hold, because of the bound (which can indeed be satisfied
/// by `SomeUnsizedType` from another crate).
//
- // FIXME: when an `EvaluatedToRecur` goes past its parent root, we
+ // FIXME: when an `EvaluatedToErrStackDependent` goes past its parent root, we
// ought to convert it to an `EvaluatedToErr`, because we know
// there definitely isn't a proof tree for that obligation. Not
// doing so is still sound -- there isn't any proof tree, so the
// branch still can't be a part of a minimal one -- but does not re-enable caching.
- EvaluatedToRecur,
+ EvaluatedToErrStackDependent,
/// Evaluation failed.
EvaluatedToErr,
}
@@ -276,15 +278,15 @@ impl EvaluationResult {
| EvaluatedToOk
| EvaluatedToOkModuloRegions
| EvaluatedToAmbig
- | EvaluatedToUnknown => true,
+ | EvaluatedToAmbigStackDependent => true,
- EvaluatedToErr | EvaluatedToRecur => false,
+ EvaluatedToErr | EvaluatedToErrStackDependent => false,
}
}
pub fn is_stack_dependent(self) -> bool {
match self {
- EvaluatedToUnknown | EvaluatedToRecur => true,
+ EvaluatedToAmbigStackDependent | EvaluatedToErrStackDependent => true,
EvaluatedToOkModuloOpaqueTypes
| EvaluatedToOk
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 27a1e64a7..048df367b 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -233,6 +233,27 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
}
}
+/// Why a specific goal has to be proven.
+///
+/// This is necessary as we treat nested goals different depending on
+/// their source.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum GoalSource {
+ Misc,
+ /// We're proving a where-bound of an impl.
+ ///
+ /// FIXME(-Znext-solver=coinductive): Explain how and why this
+ /// changes whether cycles are coinductive.
+ ///
+ /// This also impacts whether we erase constraints on overflow.
+ /// Erasing constraints is generally very useful for perf and also
+ /// results in better error messages by avoiding spurious errors.
+ /// We do not erase overflow constraints in `normalizes-to` goals unless
+ /// they are from an impl where-clause. This is necessary due to
+ /// backwards compatability, cc trait-system-refactor-initiatitive#70.
+ ImplWhereBound,
+}
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum IsNormalizesToHack {
Yes,
diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs
index e9e9cc418..4f90af0a2 100644
--- a/compiler/rustc_middle/src/traits/solve/cache.rs
+++ b/compiler/rustc_middle/src/traits/solve/cache.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::sync::Lock;
use rustc_query_system::cache::WithDepNode;
use rustc_query_system::dep_graph::DepNodeIndex;
use rustc_session::Limit;
-/// The trait solver cache used by `-Ztrait-solver=next`.
+/// The trait solver cache used by `-Znext-solver`.
///
/// FIXME(@lcnr): link to some official documentation of how
/// this works.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index a5916c4ab..77d112d0a 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -19,8 +19,8 @@
//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
use super::{
- CandidateSource, Canonical, CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution,
- QueryInput, QueryResult,
+ CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack,
+ NoSolution, QueryInput, QueryResult,
};
use crate::{infer::canonical::CanonicalVarValues, ty};
use format::ProofTreeFormatter;
@@ -115,13 +115,15 @@ impl Debug for Probe<'_> {
pub enum ProbeStep<'tcx> {
/// We added a goal to the `EvalCtxt` which will get proven
/// the next time `EvalCtxt::try_evaluate_added_goals` is called.
- AddGoal(CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
+ AddGoal(GoalSource, CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
/// The inside of a `EvalCtxt::try_evaluate_added_goals` call.
EvaluateGoals(AddedGoalsEvaluation<'tcx>),
/// A call to `probe` while proving the current goal. This is
/// used whenever there are multiple candidates to prove the
/// current goalby .
NestedProbe(Probe<'tcx>),
+ CommitIfOkStart,
+ CommitIfOkSuccess,
}
/// What kind of probe we're in. In case the probe represents a candidate, or
@@ -142,6 +144,9 @@ pub enum ProbeKind<'tcx> {
/// Used in the probe that wraps normalizing the non-self type for the unsize
/// trait, which is also structurally matched on.
UnsizeAssembly,
+ /// A call to `EvalCtxt::commit_if_ok` which failed, causing the work
+ /// to be discarded.
+ CommitIfOk,
/// During upcasting from some source object to target object type, used to
/// do a probe to find out what projection type(s) may be used to prove that
/// the source type upholds all of the target type's object bounds.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 4b73d8e41..4e2207ed5 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -109,6 +109,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
ProbeKind::UpcastProjectionCompatibility => {
writeln!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
}
+ ProbeKind::CommitIfOk => {
+ writeln!(self.f, "COMMIT_IF_OK:")
+ }
ProbeKind::MiscCandidate { name, result } => {
writeln!(self.f, "CANDIDATE {name}: {result:?}")
}
@@ -120,9 +123,17 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
self.nested(|this| {
for step in &probe.steps {
match step {
- ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
+ ProbeStep::AddGoal(source, goal) => {
+ let source = match source {
+ GoalSource::Misc => "misc",
+ GoalSource::ImplWhereBound => "impl where-bound",
+ };
+ writeln!(this.f, "ADDED GOAL ({source}): {goal:?}")?
+ }
ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
+ ProbeStep::CommitIfOkStart => writeln!(this.f, "COMMIT_IF_OK START")?,
+ ProbeStep::CommitIfOkSuccess => writeln!(this.f, "COMMIT_IF_OK SUCCESS")?,
}
}
Ok(())
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index e48b46d12..6db427064 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -72,7 +72,7 @@ impl OverlapMode {
.as_local()
.into_iter()
.flat_map(|local_def_id| {
- tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(local_def_id))
+ tcx.hir().attrs(tcx.local_def_id_to_hir_id(local_def_id))
})
.find(|attr| attr.has_name(sym::rustc_strict_coherence))
.map(|attr| attr.span);