diff options
Diffstat (limited to 'compiler/rustc_middle/src/traits')
-rw-r--r-- | compiler/rustc_middle/src/traits/mod.rs | 135 | ||||
-rw-r--r-- | compiler/rustc_middle/src/traits/query.rs | 11 | ||||
-rw-r--r-- | compiler/rustc_middle/src/traits/select.rs | 36 | ||||
-rw-r--r-- | compiler/rustc_middle/src/traits/solve.rs | 21 | ||||
-rw-r--r-- | compiler/rustc_middle/src/traits/solve/cache.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_middle/src/traits/solve/inspect.rs | 11 | ||||
-rw-r--r-- | compiler/rustc_middle/src/traits/solve/inspect/format.rs | 13 | ||||
-rw-r--r-- | compiler/rustc_middle/src/traits/specialization_graph.rs | 2 |
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); |